<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646;</title><link>https://academy.hsoub.com/programming/python/page/2/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646;</description><language>ar</language><item><title>&#x627;&#x644;&#x643;&#x62A;&#x627;&#x628;&#x629; &#x641;&#x64A; &#x645;&#x633;&#x62A;&#x646;&#x62F;&#x627;&#x62A; &#x625;&#x643;&#x633;&#x644; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x644;&#x63A;&#x629; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646; Python</title><link>https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D9%81%D9%8A-%D9%85%D8%B3%D8%AA%D9%86%D8%AF%D8%A7%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-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2375/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_07/---------------.png.fc62bd4565fa416ded1074396be6a141.png" /></p>
<p>
	تعرّفنا في <a href="https://academy.hsoub.com/programming/python/%D9%82%D8%B1%D8%A7%D8%A1%D8%A9-%D9%85%D8%B3%D8%AA%D9%86%D8%AF%D8%A7%D8%AA-%D8%AC%D8%AF%D8%A7%D9%88%D9%84-%D8%A5%D9%83%D8%B3%D9%84-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2374/" rel="">المقال السابق</a> على كيفية قراءة مستندات إكسل باستخدام لغة بايثون، وسنتعرّف في هذا المقال على كيفية كتابة مستندات إكسل باستخدام <a href="https://academy.hsoub.com/programming/python/%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-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1815/" rel="">لغة بايثون</a>، إذ توفّر وحدة OpenPyXL الخاصة بلغة بايثون طرقًا لكتابة البيانات، مما يعني أن برامجك يمكنها إنشاء ملفات جداول البيانات وتعديلها، ومن السهل إنشاء جداول بيانات تحتوي على آلاف الصفوف من البيانات باستخدام بايثون.
</p>

<h2 id="">
	إنشاء وحفظ مستندات إكسل
</h2>

<p>
	استدعِ الدالة <code>openpyxl.Workbook()‎</code> لإنشاء كائن مصنف <code>Workbook</code> جديد وفارغ، لذا أدخِل ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_9" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="typ">Workbook</span><span class="pun">()</span><span class="pln"> </span><span class="com"># إنشاء مصنف فارغ</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">sheetnames </span><span class="com"># يبدأ المصنف بورقة واحدة</span><span class="pln">
</span><span class="pun">[</span><span class="str">'Sheet'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">active
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">title
</span><span class="str">'Sheet'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">title </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Meat Eggs Sheet'</span><span class="pln"> </span><span class="com"># تغيير العنوان</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">sheetnames
</span><span class="pun">[</span><span class="str">'Meat Eggs Sheet'</span><span class="pun">]</span></pre>

<p>
	سيبدأ المصنف بورقة واحدة تُسمَّى "Sheet"، ويمكنك تغيير اسم الورقة من خلال تخزين سلسلة نصية جديدة في السمة Attribute الخاصة بها وهي <code>title</code>.
</p>

<p>
	لن يُحفظ ملف جدول البيانات عند تعديل كائن <code>Workbook</code> أو أوراقه وخلاياه حتى استدعاء تابع المصنف <code>save()‎</code>. أدخِل ما يلي في الصدفة التفاعلية (مع الملف <code>example.xlsx</code> في مجلد العمل الحالي):
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_11" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="pln">load_workbook</span><span class="pun">(</span><span class="str">'example.xlsx'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">active
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">title </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Spam Spam Spam'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">save</span><span class="pun">(</span><span class="str">'example_copy.xlsx'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># حفظ المصنف</span></pre>

<p>
	غيّرنا اسم الورقة، وحفظنا التغييرات من خلال تمرير اسم الملف كسلسلة نصية إلى التابع <code>save()‎</code>. يؤدي تمرير اسم ملف مختلف عن الاسم الأصلي -مثل الاسم <code>'example_copy.xlsx'</code>- إلى حفظ التغييرات في نسخة من جدول البيانات.
</p>

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

<h2 id="-1">
	إنشاء وحذف الأوراق
</h2>

<p>
	يمكن إضافة الأوراق وحذفها من المصنف باستخدام التابع <code>create_sheet()‎</code> والعامل <code>del</code>. إذًا لندخِل ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_13" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="typ">Workbook</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">sheetnames
</span><span class="pun">[</span><span class="str">'Sheet'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">create_sheet</span><span class="pun">()</span><span class="pln"> </span><span class="com"># إضافة ورقة جديدة</span><span class="pln">
</span><span class="pun">&lt;</span><span class="typ">Worksheet</span><span class="pln"> </span><span class="str">"Sheet1"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">sheetnames
</span><span class="pun">[</span><span class="str">'Sheet'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="com"># إنشاء ورقة جديدة في الفهرس 0</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">create_sheet</span><span class="pun">(</span><span class="pln">index</span><span class="pun">=</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> title</span><span class="pun">=</span><span class="str">'First Sheet'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="typ">Worksheet</span><span class="pln"> </span><span class="str">"First Sheet"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">sheetnames
</span><span class="pun">[</span><span class="str">'First Sheet'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Sheet'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">create_sheet</span><span class="pun">(</span><span class="pln">index</span><span class="pun">=</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> title</span><span class="pun">=</span><span class="str">'Middle Sheet'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="typ">Worksheet</span><span class="pln"> </span><span class="str">"Middle Sheet"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">sheetnames
</span><span class="pun">[</span><span class="str">'First Sheet'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Sheet'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Middle Sheet'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">]</span></pre>

<p>
	يعيد التابع <code>create_sheet()‎</code> كائن <code>Worksheet</code> جديد اسمه <code>SheetX</code>، والذي ضُبِط افتراضيًا ليكون الورقة الأخيرة في المصنف. يمكن اختياريًا تحديد فهرس واسم الورقة الجديدة باستخدام وسطاء الكلمات المفتاحية Keyword Arguments التي هي <code>index</code> و <code>title</code>.
</p>

<p>
	لنتابع المثال السابق من خلال كتابة ما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_15" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">sheetnames
</span><span class="pun">[</span><span class="str">'First Sheet'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Sheet'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Middle Sheet'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">del</span><span class="pln"> wb</span><span class="pun">[</span><span class="str">'Middle Sheet'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">del</span><span class="pln"> wb</span><span class="pun">[</span><span class="str">'Sheet1'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">sheetnames
</span><span class="pun">[</span><span class="str">'First Sheet'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Sheet'</span><span class="pun">]</span></pre>

<p>
	يمكنك استخدام العامل <code>del</code> لحذف ورقة من مصنف، وهذا يماثل استخدامه لحذف زوج مفتاح-قيمة من القاموس.
</p>

<p>
	<strong>ملاحظة</strong>: تذكّر استدعاء التابع <code>save()‎</code> لحفظ التغييرات بعد إضافة أوراق إلى المصنف أو حذفها منه.
</p>

<h2 id="-2">
	كتابة القيم في الخلايا
</h2>

<p>
	تشبه كتابة القيم في الخلايا إلى حدٍ كبير كتابة القيم في المفاتيح الموجودة ضمن القاموس. إذًا لندخل ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_17" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="typ">Workbook</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">[</span><span class="str">'Sheet'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'A1'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Hello, world!'</span><span class="pln"> </span><span class="com"># تعديل قيمة الخلية</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'A1'</span><span class="pun">].</span><span class="pln">value
</span><span class="str">'Hello, world!'</span></pre>

<p>
	إذا كان لديك إحداثيات الخلية <a href="https://wiki.hsoub.com/Python/str" rel="external">كسلسلة نصية</a>، فيمكنك استخدامها بالطريقة نفسها لاستخدام مفتاح القاموس في الكائن <code>Worksheet</code> لتحديد الخلية التي تريد الكتابة فيها.
</p>

<h2 id="-3">
	تطبيق عملي: تحديث جدول بيانات
</h2>

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

<p style="text-align: center;">
	<img alt="01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="154242" data-ratio="50.30" data-unique="tzunwdg5g" width="674" src="https://academy.hsoub.com/uploads/monthly_2024_07/01.png.a40534b7e957c3fcfe8a7a0928d23e3c.png">
</p>

<p style="text-align: center;">
	جدول بيانات مبيعات المنتجات
</p>

<p>
	يمثّل كل صف في هذا الجدول عملية بيع واحدة، والأعمدة هي نوع المنتج المباع (A)، والتكلفة لكل كيلوجرام من هذا المنتج (B)، وعدد الكيلوجرامات المباعة (C)، وإجمالي الإيرادات من عمليات البيع (D). يُضبَط عمود "الإجمالي TOTAL" على صيغة إكسل <code>‎=ROUND(B3*C3, 2)‎</code> التي تضرب تكلفة كل كيلوجرام بعدد الكيلوجرامات المُباعة وتقريب النتيجة إلى أقرب سنت. ستحدّث الخلايا الموجودة في العمود TOTAL نفسها تلقائيًا باستخدام هذه الصيغة في حالة وجود تغيير في العمود B أو C.
</p>

<p>
	لنفترض إدخال أسعار الثوم والكرفس والليمون بصورة غير صحيحة، مما يتركك أمام مهمة مملة تتمثل في المرور على آلاف الصفوف في جدول البيانات لتحديث تكلفة الكيلوجرام الواحد لصفوف الثوم Garlic والكرفس Celery والليمون Lemon. لا يمكنك إجراء عملية بحث واستبدال "find-and-replace" بسيطة للسعر بسبب وجود عناصر أخرى لها السعر نفسه ولا نريد تغييرها بصورة خاطئة. قد يستغرق تنفيذ ذلك يدويًا ساعات بالنسبة لآلاف الصفوف، ولكن يمكنك كتابة برنامج يمكنه إنجاز ذلك في ثوانٍ، حيث يطبّق برنامجك ما يلي:
</p>

<ol>
	<li>
		يتكرر على جميع الصفوف ضمن حلقة.
	</li>
	<li>
		إذا كان الصف للثوم أو الكرفس أو الليمون، فسيغيِّر السعر.
	</li>
</ol>

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

<ol>
	<li>
		فتح ملف جدول البيانات.
	</li>
	<li>
		التحقق مما إذا كانت القيمة الموجودة في العمود A هي الكرفس <code>Celery</code> أو الثوم <code>Garlic</code> أو الليمون <code>Lemon</code> لجميع الصفوف.
	</li>
	<li>
		إذا كان الأمر كذلك، فسيتحدّث السعر في العمود B.
	</li>
	<li>
		حفظ جدول البيانات في ملف جديد حتى لا تفقد جدول البيانات القديم.
	</li>
</ol>

<h3 id="-4">
	الخطوة الأولى: إعداد هيكل البيانات باستخدام معلومات التحديث
</h3>

<p>
	إليك الأسعار التي يجب تحديثها:
</p>

<table>
	<thead>
		<tr>
			<th>
				المنتج
			</th>
			<th>
				السعر
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				الكرفس Celery
			</td>
			<td>
				‫1.19
			</td>
		</tr>
		<tr>
			<td>
				الثوم Garlic
			</td>
			<td>
				‫3.07
			</td>
		</tr>
		<tr>
			<td>
				الليمون Lemon
			</td>
			<td>
				‫1.27
			</td>
		</tr>
	</tbody>
</table>

<p>
	ويمكنك كتابة الشيفرة البرمجية التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_19" style=""><span class="kwd">if</span><span class="pln"> produceName </span><span class="pun">==</span><span class="pln"> </span><span class="str">'Celery'</span><span class="pun">:</span><span class="pln">
    cellObj </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1.19</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> produceName </span><span class="pun">==</span><span class="pln"> </span><span class="str">'Garlic'</span><span class="pun">:</span><span class="pln">
    cellObj </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3.07</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> produceName </span><span class="pun">==</span><span class="pln"> </span><span class="str">'Lemon'</span><span class="pun">:</span><span class="pln">
    cellObj </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1.27</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_21" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># updateProduce.py - تصحيح أسعار المنتجات في جدول بيانات المبيعات</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> openpyxl

wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="pln">load_workbook</span><span class="pun">(</span><span class="str">'produceSales.xlsx'</span><span class="pun">)</span><span class="pln">
sheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">[</span><span class="str">'Sheet'</span><span class="pun">]</span><span class="pln">

</span><span class="com"># أنواع المنتجات وأسعارها المُحدَّثة</span><span class="pln">
PRICE_UPDATES </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'Garlic'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3.07</span><span class="pun">,</span><span class="pln">
                 </span><span class="str">'Celery'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.19</span><span class="pun">,</span><span class="pln">
                 </span><span class="str">'Lemon'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.27</span><span class="pun">}</span><span class="pln">

</span><span class="com"># التكرار على جميع الصفوف وتحديث الأسعار</span></pre>

<p>
	احفظ الملف بالاسم <code>updateProduce.py</code>. إذا أردتَ تحديث جدول البيانات مرة أخرى، فيجب تحديث القاموس <code>PRICE_UPDATES</code> فقط دون تغيير أي شيفرة برمجية أخرى.
</p>

<h3 id="-5">
	الخطوة الثانية: التحقق من كافة الصفوف وتحديث الأسعار غير الصحيحة
</h3>

<p>
	سيتكرر الجزء التالي من البرنامج على كافة الصفوف الموجودة في جدول البيانات، لذا أضِف الشيفرة البرمجية التالية إلى نهاية الملف <code>updateProduce.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_23" style=""><span class="pln"> </span><span class="com">#! python3</span><span class="pln">
   </span><span class="com"># updateProduce.py - تصحيح أسعار المنتجات في جدول بيانات المبيعات</span><span class="pln">

   </span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">

   </span><span class="com"># التكرار على جميع الصفوف وتحديث الأسعار</span><span class="pln">
</span><span class="pun">➊</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> rowNum </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">max_row</span><span class="pun">):</span><span class="pln">    </span><span class="com"># تخطي الصف الأول</span><span class="pln">
    </span><span class="pun">➋</span><span class="pln"> produceName </span><span class="pun">=</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">cell</span><span class="pun">(</span><span class="pln">row</span><span class="pun">=</span><span class="pln">rowNum</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">=</span><span class="lit">1</span><span class="pun">).</span><span class="pln">value
    </span><span class="pun">➌</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> produceName </span><span class="kwd">in</span><span class="pln"> PRICE_UPDATES</span><span class="pun">:</span><span class="pln">
          sheet</span><span class="pun">.</span><span class="pln">cell</span><span class="pun">(</span><span class="pln">row</span><span class="pun">=</span><span class="pln">rowNum</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">=</span><span class="lit">2</span><span class="pun">).</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> PRICE_UPDATES</span><span class="pun">[</span><span class="pln">produceName</span><span class="pun">]</span><span class="pln">

</span><span class="pun">➍</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">save</span><span class="pun">(</span><span class="str">'updatedProduceSales.xlsx'</span><span class="pun">)</span></pre>

<p>
	نكرّر الشيفرة البرمجية على الصفوف بدءًا من الصف 2، لأن الصف 1 هو ترويسة الجدول ➊، ونخزّن الخلية الموجودة في العمود 1 (أي العمود A) في المتغير <code>produceName</code> ➋، حيث إذا كان هذا المتغير موجودًا بوصفه مفتاحًا في قاموس <code>PRICE_UPDATES</code> ➌، فيجب أن تعلم أن هذا الصف يجب تصحيح سعره، وسيكون السعر الصحيح في <code>PRICE_UPDATES[produceName]‎</code>.
</p>

<p>
	لاحظ مدى نظافة شيفرتك باستخدام قاموس <code>PRICE_UPDATES</code>، إذ لا توجد سوى تعليمة <code>if</code> واحدة فقط بدلًا من استخدام شيفرة تحتوي التعليمة <code>if produceName == 'Garlic':‎</code> مثلًا التي تكون ضرورية لكل نوعٍ من المنتجات يجب تحديثه. بما أن هذه الشيفرة البرمجية تستخدم قاموس <code>PRICE_UPDATES</code> بدلًا من كتابة شيفرة ثابتة لأسماء المنتجات وأسعارها المُحدَّثة ضمن <a href="https://wiki.hsoub.com/Python/for" rel="external">حلقة for</a>، فهذا يعني أنك ستعدّل قاموس <code>PRICE_UPDATES</code> فقط دون تعديل الشيفرة البرمجية، إذا احتاج جدول بيانات مبيعات المنتجات تغييراتٍ إضافية.
</p>

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

<p>
	<strong>ملاحظة</strong>: لا تنسَ أنه يمكنك <a href="https://nostarch.com/automatestuff2/" rel="external nofollow">تنزيل</a> الشيفرة المصدرية الكاملة لهذا البرنامج.
</p>

<h3 id="-6">
	أفكار لبرامج مماثلة
</h3>

<p>
	يستخدم العديد من العاملين في وظائف مكتبية <a href="https://academy.hsoub.com/apps/productivity/office/microsoft-excel/%D8%A5%D8%AF%D8%AE%D8%A7%D9%84-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%B9%D8%AF%D9%8A%D9%84%D9%87%D8%A7-%D9%88%D8%AA%D8%AD%D8%B1%D9%8A%D8%B1%D9%87%D8%A7-%D9%81%D9%8A-%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D8%A5%D9%83%D8%B3%D9%84-exel-r934/" rel="">جداولَ بيانات إكسل</a> طوال الوقت، لذا قد يكون البرنامج الذي يمكنه تعديل ملفات إكسل وكتابتها تلقائيًا مفيدًا جدًا لهم، إذ يمكن أن يفعل مثل هذا البرنامج الأمور التالية:
</p>

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

<h2 id="fontstyle">
	ضبط نمط الخط Font Style في الخلايا
</h2>

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

<p>
	يمكنك تخصيص أنماط الخطوط في الخلايا من خلال استيراد الدالة <code>Font()‎</code> من الوحدة <code>openpyxl.styles</code>، مما يتيح لك كتابة <code>Font()‎</code> بدلًا من <code>openpyxl.styles.Font()‎</code> اختصارًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_25" style=""><span class="kwd">from</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="pln">styles </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Font</span></pre>

<p>
	ينشئ المثال التالي مصنفًا جديدًا ويضبط الخلية A1 ليكون الخط فيها خطًا مائلًا وبحجم 24 نقطة. إذًا لندخِل ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_27" style=""><span class="pln">  </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl
  </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="pln">styles </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Font</span><span class="pln">
  </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="typ">Workbook</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">[</span><span class="str">'Sheet'</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"> italic24Font </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Font</span><span class="pun">(</span><span class="pln">size</span><span class="pun">=</span><span class="lit">24</span><span class="pun">,</span><span class="pln"> italic</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">)</span><span class="pln"> </span><span class="com"># إنشاء الخط</span><span class="pln">
</span><span class="pun">➋</span><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'A1'</span><span class="pun">].</span><span class="pln">font </span><span class="pun">=</span><span class="pln"> italic24Font </span><span class="com"># ت‫طبيق الخط في الخلية A1</span><span class="pln">
  </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'A1'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Hello, world!'</span><span class="pln">
  </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">save</span><span class="pun">(</span><span class="str">'styles.xlsx'</span><span class="pun">)</span></pre>

<p>
	تعيد الدالة <code>Font(size=24, italic=True)‎</code> كائن <code>Font</code> المُخزَّن في المتغير <code>italic24Font</code> ➊، وتضبط وسطاء الكلمات المفتاحية الخاصة بالدالة <code>Font()‎</code> -مثل الوسيطين <code>size</code> و <code>italic</code>- معلومات تنسيق الكائن <code>Font</code>، وإذا أسندنا الكائن <code>italic24Font</code> ➋ إلى <code>sheet['A1'].font</code>، فستُطبَّق جميع معلومات تنسيق الخط على الخلية A1.
</p>

<h2 id="font">
	كائنات الخط Font
</h2>

<p>
	يمكن ضبط السمات <code>font</code> من خلال تمرير وسطاء الكلمات المفتاحية إلى الدالة <code>Font()‎</code>، حيث يوضّح الجدول التالي وسطاء الكلمات المفتاحية المُحتمَلة للدالة <code>Font()‎</code>:
</p>

<table>
	<thead>
		<tr>
			<th>
				وسيط الكلمة المفتاحية
			</th>
			<th>
				نوع البيانات
			</th>
			<th>
				الوصف
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				<code>name</code>
			</td>
			<td>
				سلسلة نصية
			</td>
			<td>
				اسم الخط مثل <code>'Calibri'</code> أو <code>'Times New Roman'</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>size</code>
			</td>
			<td>
				عدد صحيح
			</td>
			<td>
				حجم الخط مقاسًا بالنقاط
			</td>
		</tr>
		<tr>
			<td>
				<code>bold</code>
			</td>
			<td>
				قيمة منطقية
			</td>
			<td>
				قيمته <code>True</code> إذا كان الخط عريضًا
			</td>
		</tr>
		<tr>
			<td>
				<code>italic</code>
			</td>
			<td>
				قيمة منطقية
			</td>
			<td>
				قيمته <code>True</code> إذا كان الخط مائلًا
			</td>
		</tr>
	</tbody>
</table>

<p>
	يمكنك استدعاء الدالة <code>Font()‎</code> لإنشاء كائن <code>Font</code> وتخزينه في متغير، ثم تسند السمة <code>font</code> الخاصة بكائن <code>Cell</code> إلى هذا المتغير، فمثلًا تنشئ الشيفرة البرمجية التالية تنسيقات خطوط مختلفة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_30" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="pln">styles </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Font</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="typ">Workbook</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">[</span><span class="str">'Sheet'</span><span class="pun">]</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> fontObj1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Font</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="str">'Times New Roman'</span><span class="pun">,</span><span class="pln"> bold</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'A1'</span><span class="pun">].</span><span class="pln">font </span><span class="pun">=</span><span class="pln"> fontObj1
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'A1'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Bold Times New Roman'</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> fontObj2 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Font</span><span class="pun">(</span><span class="pln">size</span><span class="pun">=</span><span class="lit">24</span><span class="pun">,</span><span class="pln"> italic</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'B3'</span><span class="pun">].</span><span class="pln">font </span><span class="pun">=</span><span class="pln"> fontObj2
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'B3'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'24 pt Italic'</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">save</span><span class="pun">(</span><span class="str">'styles.xlsx'</span><span class="pun">)</span></pre>

<p>
	نخزّن كائن <code>Font</code> في المتغير <code>fontObj1</code> الذي نسنده إلى السمة <code>font</code> الخاصة بالكائن <code>Cell</code> للخلية A1، ونكرر العملية نفسها مع كائن خط آخر لضبط خط الخلية الثانية. إذا نفّذنا الشيفرة البرمجية السابقة، فسيُضبَط تنسيق الخلايا A1 و B3 في جدول البيانات على تنسيقات الخطوط المُخصَّصة، وستبدو كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="154249" href="https://academy.hsoub.com/uploads/monthly_2024_07/02_000007.jpg.5be1a7589df209502b375645b3a66bfa.jpg" rel=""><img alt="02 000007" class="ipsImage ipsImage_thumbnailed" data-fileid="154249" data-unique="8gwjmsg6d" src="https://academy.hsoub.com/uploads/monthly_2024_07/02_000007.jpg.5be1a7589df209502b375645b3a66bfa.jpg"> </a>
</p>

<p style="text-align: center;">
	جدول بيانات يحتوي على أنماط خطوط مُخصَّصة
</p>

<p>
	ضبطنا اسم الخط في الخلية A1 على القيمة <code>'Times New Roman'</code> والوسيط <code>bold</code> على القيمة <code>true</code>، حيث يظهر النص بالخط Times New Roman العريض، ولكننا لم نحدد حجم الخط، لذلك اُستخدِم الحجم الافتراضي للوحدة <code>openpyxl</code>، وهو الحجم 11. استخدمنا الخط المائل وبحجم 24 في الخلية B3، ولكن لم نحدد اسم الخط، لذلك اُستخدِم الخط الافتراضي للوحدة <code>openpyxl</code>، وهو الخط Calibri.
</p>

<h2 id="-7">
	صيغ إكسل
</h2>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_32" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'B9'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'=SUM(B1:B8)'</span></pre>

<p>
	ستؤدي التعليمة السابقة إلى تخزين الصيغة <code>‎=SUM(B1:B8)‎</code> بوصفها قيمةً في الخلية B9، مما يؤدي إلى ضبط الخلية B9 على صيغة تحسب مجموع القيم في الخلايا من B1 إلى B8 كما في الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="154240" href="https://academy.hsoub.com/uploads/monthly_2024_07/03_000100.jpg.3ebfabc183341a41c134319bf96be782.jpg" rel=""><img alt="03 000100" class="ipsImage ipsImage_thumbnailed" data-fileid="154240" data-unique="a79gzp5wn" src="https://academy.hsoub.com/uploads/monthly_2024_07/03_000100.jpg.3ebfabc183341a41c134319bf96be782.jpg"> </a>
</p>

<p>
	تحتوي الخلية B9 على الصيغة ‎=SUM(B1:B8)‎ التي تجمع القيم الموجودة في الخلايا من B1 إلى B8
</p>

<p>
	تُضبَط صيغ إكسل مثل أيّ قيمة نصية أخرى في الخلية. إذًا لندخِل ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_34" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="typ">Workbook</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">active
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'A1'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">200</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'A2'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">300</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'A3'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'=SUM(A1:A2)'</span><span class="pln"> </span><span class="com"># ضبط الصيغة</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">save</span><span class="pun">(</span><span class="str">'writeFormula.xlsx'</span><span class="pun">)</span></pre>

<p>
	ضبطنا الخلايا A1 و A2 على القيمتين 200 و 300 على التوالي، وضبطنا القيمة الموجودة في الخلية A3 على صيغة تجمع القيم الموجودة في الخليتين A1 و A2، وبالتالي ستظهر قيمة الخلية A3 على أنها 500 عند فتح جدول البيانات في إكسل.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_36" style=""><span class="pun">=</span><span class="pln">IFERROR</span><span class="pun">(</span><span class="pln">TRIM</span><span class="pun">(</span><span class="pln">IF</span><span class="pun">(</span><span class="pln">LEN</span><span class="pun">(</span><span class="pln">VLOOKUP</span><span class="pun">(</span><span class="pln">F7</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Sheet2</span><span class="pun">!</span><span class="pln">$A$1</span><span class="pun">:</span><span class="pln">$B$10000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> FALSE</span><span class="pun">))&gt;</span><span class="lit">0</span><span class="pun">,</span><span class="pln">SUBSTITUTE</span><span class="pun">(</span><span class="pln">VLOOKUP</span><span class="pun">(</span><span class="pln">F7</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Sheet2</span><span class="pun">!</span><span class="pln">$A$1</span><span class="pun">:</span><span class="pln">$B$10000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> FALSE</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="str">""</span><span class="pun">)),</span><span class="pln"> </span><span class="str">""</span><span class="pun">)</span></pre>

<p>
	لاحظ أن شيفرة بايثون البرمجية أكثر قابلية للقراءة من الصيغة السابقة.
</p>

<h2 id="-8">
	تعديل الصفوف والأعمدة
</h2>

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

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

<h3 id="-9">
	ضبط ارتفاع الصف وعرض العمود
</h3>

<p>
	تمتلك كائنات <code>Worksheet</code> سمات <code>row_dimensions</code> و <code>column_dimensions</code> التي تتحكم في ارتفاع الصفوف وعرض الأعمدة. إذًا لندخِل ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_38" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="typ">Workbook</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">active
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'A1'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Tall row'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'B2'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Wide column'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="com"># ضبط الارتفاع والعرض</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">row_dimensions</span><span class="pun">[</span><span class="lit">1</span><span class="pun">].</span><span class="pln">height </span><span class="pun">=</span><span class="pln"> </span><span class="lit">70</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">column_dimensions</span><span class="pun">[</span><span class="str">'B'</span><span class="pun">].</span><span class="pln">width </span><span class="pun">=</span><span class="pln"> </span><span class="lit">20</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">save</span><span class="pun">(</span><span class="str">'dimensions.xlsx'</span><span class="pun">)</span></pre>

<p>
	تُعَد السمات <code>row_dimensions</code> و <code>column_dimensions</code> الخاصة بالورقة قيمًا تشبه القاموس، إذ تحتوي السمة <code>row_dimensions</code> على كائنات <code>RowDimension</code> وتحتوي السمة <code>column_dimensions</code> على كائنات <code>ColumnDimension</code>. يمكنك الوصول إلى أحد الكائنات باستخدام رقم الصف (في مثالنا 1 أو 2) في <code>row_dimensions</code>، ويمكنك الوصول إلى أحد الكائنات باستخدام حرف العمود (في مثالنا A أو B) في <code>column_dimensions</code>.
</p>

<p>
	يبدو جدول البيانات <code>dimensions.xlsx</code> كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="154246" href="https://academy.hsoub.com/uploads/monthly_2024_07/04_000046.jpg.48d6ca232f6874a90e65c4912a69fec2.jpg" rel=""><img alt="04 000046" class="ipsImage ipsImage_thumbnailed" data-fileid="154246" data-unique="pgep4w276" src="https://academy.hsoub.com/uploads/monthly_2024_07/04_000046.jpg.48d6ca232f6874a90e65c4912a69fec2.jpg"> </a>
</p>

<p style="text-align: center;">
	ضبطنا الصف 1 والعمود B على ارتفاع وعرض أكبر
</p>

<p>
	يمكنك ضبط ارتفاع الكائن <code>RowDimension</code> بعد الحصول عليه، ويمكنك ضبط عرض الكائن <code>ColumnDimension</code> بعد الحصول عليه. يمكن ضبط ارتفاع الصف ليكون عددًا صحيحًا أو عشريًا قيمته بين 0 و 409، إذ تمثّل هذه القيمة الارتفاع المُقاس بالنقاط، حيث تساوي النقطة الواحدة 1/72 من البوصة، ويكون ارتفاع الصف الافتراضي 12.75. يمكن ضبط عرض العمود ليكون عددًا صحيحًا أو عشريًا قيمته بين 0 و255، إذ تمثّل هذه القيمة عدد المحارف التي يمكن عرضها في الخلية بحجم الخط الافتراضي (11 نقطة)، ويكون عرض العمود الافتراضي 8.43 محرفًا. تُخفَى الأعمدة التي يبلغ عرضها 0 أو الصفوف التي يبلغ ارتفاعها 0 عن المستخدم.
</p>

<h3 id="-10">
	دمج وإلغاء دمج الخلايا
</h3>

<p>
	يمكن دمج منطقة مستطيلة من الخلايا في خلية واحدة باستخدام التابع <code>merge_cells()‎</code> الخاص بالورقة. إذًا لندخِل ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_40" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="typ">Workbook</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">active
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">merge_cells</span><span class="pun">(</span><span class="str">'A1:D3'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># دمج جميع هذه الخلايا</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'A1'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Twelve cells merged together.'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">merge_cells</span><span class="pun">(</span><span class="str">'C5:D5'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># دمج هاتين الخليتين</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'C5'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Two merged cells.'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">save</span><span class="pun">(</span><span class="str">'merged.xlsx'</span><span class="pun">)</span></pre>

<p>
	وسيط التابع <code>merge_cells()‎</code> هو سلسلة نصية واحدة من الخلايا العلوية اليسرى والسفلية اليمنى للمنطقة المستطيلة المُراد دمجها، حيث تدمج ‎<code>'A1:D3'</code>‎ اثنتا عشر خلية في خلية واحدة، ويمكنك ضبط قيمة هذه الخلايا المدموجة من خلال ضبط قيمة الخلية العلوية اليسرى لمجموعة الخلايا المدموجة.
</p>

<p>
	سيبدو الملف <code>merged.xlsx</code> كما يلي عند تشغيل الشيفرة البرمجية السابقة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="154243" href="https://academy.hsoub.com/uploads/monthly_2024_07/05_000140.jpg.8f65f4cd6da223477ab4ae6edbb30c14.jpg" rel=""><img alt="05 000140" class="ipsImage ipsImage_thumbnailed" data-fileid="154243" data-unique="hieu3tifz" src="https://academy.hsoub.com/uploads/monthly_2024_07/05_000140.jpg.8f65f4cd6da223477ab4ae6edbb30c14.jpg"> </a>
</p>

<p style="text-align: center;">
	الخلايا المدموجة في جدول البيانات
</p>

<p>
	يمكن إلغاء دمج الخلايا من خلال استدعاء التابع <code>unmerge_cells()‎</code> الخاص بالورقة. إذًا لندخِل ما يلي الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_42" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="pln">load_workbook</span><span class="pun">(</span><span class="str">'merged.xlsx'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">active
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">unmerge_cells</span><span class="pun">(</span><span class="str">'A1:D3'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># فصل هذه الخلايا عن بعضها</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">unmerge_cells</span><span class="pun">(</span><span class="str">'C5:D5'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">save</span><span class="pun">(</span><span class="str">'merged.xlsx'</span><span class="pun">)</span></pre>

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

<h3 id="-11">
	تثبيت الأجزاء
</h3>

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

<p>
	يمكن إلغاء تثبيت جميع الأجزاء من خلال ضبط السمة <code>freeze_panes</code> على القيمة <code>None</code> أو <code>'A1'</code>. يوضح الجدول التالي الصفوف والأعمدة التي ستُثبَّت في بعض الأمثلة عند ضبط قيمة السمة <code>freeze_panes</code>:
</p>

<table>
	<thead>
		<tr>
			<th>
				ضبط السمة <code>freeze_panes</code>
			</th>
			<th>
				الصفوف والأعمدة المُثبَّتة
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				‎<code>sheet.freeze_panes = 'A2'</code>‎
			</td>
			<td>
				الصف 1
			</td>
		</tr>
		<tr>
			<td>
				‎<code>sheet.freeze_panes = 'B1'</code>‎
			</td>
			<td>
				العمود A
			</td>
		</tr>
		<tr>
			<td>
				‎<code>sheet.freeze_panes = 'C1'</code>‎
			</td>
			<td>
				العمودان A و B
			</td>
		</tr>
		<tr>
			<td>
				‎<code>sheet.freeze_panes = 'C2'</code>‎
			</td>
			<td>
				الصف 1 والعمودان A و B
			</td>
		</tr>
		<tr>
			<td>
				‎<code>sheet.freeze_panes = 'A1'</code>‎ أو <code>sheet.freeze_panes = None</code>
			</td>
			<td>
				لا توجد أجزاء مُثبَّتة
			</td>
		</tr>
	</tbody>
</table>

<p>
	تأكّد من حصولك على <a href="https://nostarch.com/automatestuff2/" rel="external nofollow">جدول بيانات مبيعات المنتجات</a>، ثم أدخِل ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_44" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="pln">load_workbook</span><span class="pun">(</span><span class="str">'produceSales.xlsx'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">active
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">freeze_panes </span><span class="pun">=</span><span class="pln"> </span><span class="str">'A2'</span><span class="pln"> </span><span class="com"># تثبيت الصفوف‫ الموجودة أعلى الصف A2</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">save</span><span class="pun">(</span><span class="str">'freezeExample.xlsx'</span><span class="pun">)</span></pre>

<p>
	إذا ضبطتَ السمة <code>freeze_panes</code> على القيمة <code>'A2'</code>، فسيُعرَض الصف 1 دائمًا بغض النظر عن المكان الذي ينتقل إليه المستخدم عند التمرير في جدول البيانات، ويمكنك رؤية ذلك في الشكل التالي:
</p>

<p style="text-align: center;">
	<img alt="06_000083.png" class="ipsImage ipsImage_thumbnailed" data-fileid="154247" data-ratio="34.44" data-unique="q3qbob80d" width="694" src="https://academy.hsoub.com/uploads/monthly_2024_07/06_000083.png.eaf087f7df0c385cfc0e3eaa07a50fdd.png">
</p>

<p>
	يكون الصف 1 مرئيًا دائمًا حتى عندما يمرّر المستخدم جدول البيانات إلى الأسفل، إذا ضبطنا السمة <code>freeze_panes</code> على القيمة <code>'A2'</code>
</p>

<h2 id="charts">
	المخططات Charts
</h2>

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

<ol>
	<li>
		إنشاء كائن <code>Reference</code> من خلايا المنطقة المستطيلة المُحدّدة.
	</li>
	<li>
		إنشاء كائن <code>Series</code> من خلال تمرير الكائن <code>Reference</code>.
	</li>
	<li>
		إنشاء كائن <code>Chart</code>.
	</li>
	<li>
		إلحاق كائن <code>Series</code> بكائن <code>Chart</code>.
	</li>
	<li>
		إضافة الكائن <code>Chart</code> إلى الكائن <code>Worksheet</code> مع تحديد الخلية التي يجب أن تكون في الزاوية العلوية اليسرى من المخطط اختياريًا.
	</li>
</ol>

<p>
	يمكنك إنشاء كائنات <code>Reference</code> من خلال استدعاء الدالة <code>openpyxl.chart.Reference()‎</code> وتمرير ثلاثة وسطاء هي:
</p>

<ol>
	<li>
		كائن <code>Worksheet</code> الذي يحتوي على بيانات مخططك.
	</li>
	<li>
		مجموعة <a href="https://wiki.hsoub.com/Python/tuple" rel="external">Tuple</a> مكونة من عددين صحيحين، حيث تمثل هذه المجموعة الخلية العلوية اليسرى من خلايا المنطقة المستطيلة المُحدَّدة التي تحتوي على بيانات مخططك، ويمثل العددُ الصحيح الأول في المجموعة الصفَّ، ويمثل العدد الصحيح الثاني العمود. لاحظ أن العدد 1 هو الصف الأول وليس العدد 0.
	</li>
	<li>
		مجموعة مكونة من عددين صحيحين، حيث تمثل هذه المجموعة الخلية السفلية اليمنى من خلايا المنطقة المستطيلة المُحدَّدة التي تحتوي على بيانات مخططك، ويمثل العدد الصحيح الأول في المجموعة الصف، ويمثل العدد الصحيح الثاني العمود.
	</li>
</ol>

<p>
	يوضح الشكل التالي بعض النماذج من وسطاء الإحداثيات:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="154245" href="https://academy.hsoub.com/uploads/monthly_2024_07/07_000099.jpg.7e4be4b086ff1a797728e468f9265ff8.jpg" rel=""><img alt="07 000099" class="ipsImage ipsImage_thumbnailed" data-fileid="154245" data-unique="wkkekuf5q" src="https://academy.hsoub.com/uploads/monthly_2024_07/07_000099.jpg.7e4be4b086ff1a797728e468f9265ff8.jpg"> </a>
</p>

<p>
	وهي من اليسار إلى اليمين:
</p>

<p>
	(1, 1), (10, 1); (3, 2), (6, 4); (5, 3), (5, 3)
</p>

<p>
	أدخِل مثال الصدفة التفاعلية التالي لإنشاء مخطط شريطي وإضافته إلى جدول البيانات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_46" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="typ">Workbook</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">active
</span><span class="pun">&gt;&gt;&gt;</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">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">11</span><span class="pun">):</span><span class="pln"> </span><span class="com"># إنشاء بعض ‫البيانات في العمود A</span><span class="pln">
</span><span class="pun">...</span><span class="pln">     sheet</span><span class="pun">[</span><span class="str">'A'</span><span class="pln"> </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"> i
</span><span class="pun">...</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> refObj </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="pln">chart</span><span class="pun">.</span><span class="typ">Reference</span><span class="pun">(</span><span class="pln">sheet</span><span class="pun">,</span><span class="pln"> min_col</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> min_row</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> max_col</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln">
max_row</span><span class="pun">=</span><span class="lit">10</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> seriesObj </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="pln">chart</span><span class="pun">.</span><span class="typ">Series</span><span class="pun">(</span><span class="pln">refObj</span><span class="pun">,</span><span class="pln"> title</span><span class="pun">=</span><span class="str">'First series'</span><span class="pun">)</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> chartObj </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="pln">chart</span><span class="pun">.</span><span class="typ">BarChart</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> chartObj</span><span class="pun">.</span><span class="pln">title </span><span class="pun">=</span><span class="pln"> </span><span class="str">'My Chart'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> chartObj</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">seriesObj</span><span class="pun">)</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">add_chart</span><span class="pun">(</span><span class="pln">chartObj</span><span class="pun">,</span><span class="pln"> </span><span class="str">'C5'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">save</span><span class="pun">(</span><span class="str">'sampleChart.xlsx'</span><span class="pun">)</span></pre>

<p>
	وينتج عن ذلك جدول بيانات يشبه ما يلي:
</p>

<p style="text-align: center;">
	<img alt="08_000122.png" class="ipsImage ipsImage_thumbnailed" data-fileid="154241" data-ratio="62.54" data-unique="5llm0m7cb" width="590" src="https://academy.hsoub.com/uploads/monthly_2024_07/08_000122.png.fafb5013ac769ee1bdba283d653ae81f.png">
</p>

<p style="text-align: center;">
	جدول بيانات مع مخطط مضافٍ إليه
</p>

<p>
	أنشأنا مخططًا شريطيًا من خلال استدعاء الدالة <code>openpyxl.chart.BarChart()‎</code>، ويمكنك إنشاء مخططات خطية ومخططات مبعثرة ومخططات دائرية من خلال استدعاء <a href="https://academy.hsoub.com/programming/python/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-functions-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r292/" rel="">الدوال</a> <code>openpyxl.charts.LineChart()‎</code> و <code>openpyxl.charts.LineChart()‎</code> و <code>openpyxl.charts.LineChart()‎</code>.
</p>

<h2 id="-13">
	مشاريع للتدريب
</h2>

<p>
	حاول كتابة البرامج التي تؤدي المهام التي سنوضّحها فيما يلي، لكسب خبرة عملية أكبر.
</p>

<h3 id="-14">
	برنامج لإنشاء جدول الضرب
</h3>

<p>
	أنشئ برنامج <code>multiplicationTable.py</code> الذي يأخذ العدد N من سطر الأوامر وينشئ جدول الضرب N×N في جدول بيانات إكسل، فمثلًا إذا شغّلنا البرنامج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_49" style=""><span class="pln">py multiplicationTable</span><span class="pun">.</span><span class="pln">py </span><span class="lit">6</span></pre>

<p>
	يجب أن ينشئ جدول بيانات يشبه الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="154244" href="https://academy.hsoub.com/uploads/monthly_2024_07/09_000067.jpg.5194f6e1a0acd2c2006de05fdbae0bda.jpg" rel=""><img alt="09 000067" class="ipsImage ipsImage_thumbnailed" data-fileid="154244" data-unique="h7w7kp98u" src="https://academy.hsoub.com/uploads/monthly_2024_07/09_000067.jpg.5194f6e1a0acd2c2006de05fdbae0bda.jpg"> </a>
</p>

<p style="text-align: center;">
	توليد جدول الضرب في جدول بيانات
</p>

<p>
	يجب استخدام الصف 1 والعمود A للتسميات أو عناوين الصفوف والأعمدة ويجب أن يكونا بالخط العريض.
</p>

<h3 id="-15">
	برنامج لإدراج صف فارغ
</h3>

<p>
	أنشئ برنامج <code>blankRowInserter.py</code> الذي يأخذ عددين صحيحين وسلسلة نصية لاسم الملف كوسطاء <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%A7-%D9%87%D9%88-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%9F-r353/" rel="">لسطر الأوامر</a>، حيث نسمّي العدد الصحيح الأول N والعدد الصحيح الثاني M. يجب على البرنامج إدراج صفوف فارغة بعدد M في جدول البيانات بدءًا من الصف N، فمثلًا إذا شغّلنا البرنامج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9918_51" style=""><span class="pln">python blankRowInserter</span><span class="pun">.</span><span class="pln">py </span><span class="lit">3</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> myProduce</span><span class="pun">.</span><span class="pln">xlsx</span></pre>

<p>
	يجب أن تبدو جداول البيانات "قبل" و"بعد" الإدراج كما في الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="154238" href="https://academy.hsoub.com/uploads/monthly_2024_07/10_000013.jpg.4d8a3081fb91d97de50edfad10cec647.jpg" rel=""><img alt="10 000013" class="ipsImage ipsImage_thumbnailed" data-fileid="154238" data-unique="bh8efpubu" src="https://academy.hsoub.com/uploads/monthly_2024_07/10_000013.jpg.4d8a3081fb91d97de50edfad10cec647.jpg"> </a>
</p>

<p style="text-align: center;">
	قبل (يسار) وبعد (يمين) إدراج الصفين الفارغين عند الصف 3
</p>

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

<h3 id="-16">
	برنامج لعكس خلايا جدول البيانات
</h3>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="154239" href="https://academy.hsoub.com/uploads/monthly_2024_07/11_000108.jpg.1577f0f2018cb19da6da0d74b98409df.jpg" rel=""><img alt="11 000108" class="ipsImage ipsImage_thumbnailed" data-fileid="154239" data-unique="echaiu209" src="https://academy.hsoub.com/uploads/monthly_2024_07/11_000108.jpg.1577f0f2018cb19da6da0d74b98409df.jpg"> </a>
</p>

<p style="text-align: center;">
	جدول البيانات قبل (العلوي) وبعد (السفلي)
</p>

<p>
	يمكنك كتابة هذا البرنامج باستخدام حلقات <code>for</code> متداخلة لقراءة بيانات جدول البيانات في قائمة من قوائم هيكل البيانات، ويمكن أن يحتوي هيكل البيانات على <code>sheetData[x][y]‎</code> للخلية الموجودة في العمود x والصف y. استخدم بعد ذلك <code>sheetData[y][x]‎</code> للخلية الموجودة في العمود x والصف y عند كتابة جدول البيانات الجديد.
</p>

<h3 id="-17">
	برنامج لتحويل الملفات النصية إلى جدول بيانات
</h3>

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

<p>
	استخدم التابع <code>readlines()‎</code> الخاص بالكائن <code>File</code> لإعادة قائمة من السلاسل النصية، حيث تقابل كل سلسلة نصية واحدة سطرًا في الملف. يكون السطر الأول من الملف الأول مقابلًا للعمود 1 والصف 1، ويجب كتابة السطر الثاني في العمود 1 والصف 2، وما إلى ذلك. سيُكتَب الملف التالي المقروء باستخدام التابع <code>readlines()‎</code> في العمود 2، وسيُكتَب الملف الذي يليه في العمود 3، وهكذا.
</p>

<h3 id="-18">
	برنامج لتحويل جدول بيانات إلى ملفات نصية
</h3>

<p>
	اكتب برنامجًا يؤدّي مهام البرنامج السابق بترتيب عكسي، إذ يجب أن يفتح البرنامج جدول بيانات ويكتب خلايا العمود A في ملف نصي واحد، وخلايا العمود B في ملف نصي آخر، وهكذا.
</p>

<h2 id="-19">
	الخلاصة
</h2>

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

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

<p>
	سنلقي نظرة في المقال التالي على استخدام لغة بايثون للتفاعل مع برنامج آخر لجداول بيانات، وهو تطبيق ج<a href="https://academy.hsoub.com/apps/productivity/google-drive/google-sheets/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%AC%D8%AF%D8%A7%D9%88%D9%84-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%AC%D9%88%D8%AC%D9%84-google-sheets-r295/" rel="">داول بيانات جوجل Google Sheets</a> الشهير على الإنترنت.
</p>

<p>
	ترجمة -وبتصرُّف- للقسم Writing Excel Documents من مقال <a href="https://automatetheboringstuff.com/2e/chapter13/" rel="external nofollow">Working with Excel Spreadsheets</a> لصاحبه Al Sweigart.
</p>

<h2 id="-20">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/python/%D9%82%D8%B1%D8%A7%D8%A1%D8%A9-%D9%85%D8%B3%D8%AA%D9%86%D8%AF%D8%A7%D8%AA-%D8%AC%D8%AF%D8%A7%D9%88%D9%84-%D8%A5%D9%83%D8%B3%D9%84-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2374/" rel="">قراءة مستندات جداول إكسل باستخدام لغة بايثون Python</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D8%A7%D8%B3%D8%AA%D8%AE%D8%B1%D8%A7%D8%AC-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%85%D9%86-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%B9%D8%A8%D8%B1-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2366/" rel="">استخراج البيانات من الويب عبر لغة بايثون Python</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D9%82%D8%B1%D8%A7%D8%A1%D8%A9-%D9%88%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%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-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2347/" rel="">قراءة وكتابة الملفات باستخدام لغة بايثون Python</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%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%88%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1858/" rel="">التعامل مع الملفات والمسارات في بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/apps/productivity/office/microsoft-excel/%D9%86%D8%B8%D8%B1%D8%A9-%D8%B9%D8%A7%D9%85%D8%A9-%D8%B9%D9%84%D9%89-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D8%AC-%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-microsoft-excel-r930/" rel="">نظرة عامة على برنامج مايكروسوفت إكسل Microsoft Excel</a>
	</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>
</ul>
]]></description><guid isPermaLink="false">2375</guid><pubDate>Tue, 30 Jul 2024 15:04:01 +0000</pubDate></item><item><title>&#x642;&#x631;&#x627;&#x621;&#x629; &#x645;&#x633;&#x62A;&#x646;&#x62F;&#x627;&#x62A; &#x62C;&#x62F;&#x627;&#x648;&#x644; &#x625;&#x643;&#x633;&#x644; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x644;&#x63A;&#x629; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646; Python</title><link>https://academy.hsoub.com/programming/python/%D9%82%D8%B1%D8%A7%D8%A1%D8%A9-%D9%85%D8%B3%D8%AA%D9%86%D8%AF%D8%A7%D8%AA-%D8%AC%D8%AF%D8%A7%D9%88%D9%84-%D8%A5%D9%83%D8%B3%D9%84-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2374/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_07/--------------.png.5f0fbc81da8065c503aca6a83d7564fe.png" /></p>
<p>
	قد لا نفكر في جداول البيانات بوصفها أدوات برمجية، ولكن يستخدمها الجميع تقريبًا لتنظيم المعلومات في هياكل بيانية ثنائية الأبعاد، وإجراء العمليات الحسابية باستخدام الصيغ، وعرض المخرجات على شكل مخططات، لذا سندمج <a href="https://academy.hsoub.com/programming/python/%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-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1815/" rel="">لغة بايثون</a> مع تطبيقين شائعين خاصين بجداول البيانات وهما: <a href="https://academy.hsoub.com/apps/productivity/office/microsoft-excel/%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-microsoft-excel-%D9%88%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D9%85%D8%B5%D9%86%D9%81-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r25/" rel="">مايكروسوفت إكسل Microsoft Excel</a> و<a href="https://academy.hsoub.com/apps/productivity/google-drive/google-sheets/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%AC%D8%AF%D8%A7%D9%88%D9%84-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%AC%D9%88%D8%AC%D9%84-google-sheets-r295/" rel="">جداول بيانات جوجل Google Sheets</a>.
</p>

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

<p>
	يُعَد برنامج إكسل برنامجًا خاصًا بشركة مايكروسوفت، ولكن توجد بدائل مجانية تعمل على أنظمة تشغيل ويندوز وماك macOS و<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%86%D8%B8%D8%A7%D9%85-%D9%84%D9%8A%D9%86%D9%83%D8%B3-linux-%D9%88%D8%A3%D8%A8%D8%B1%D8%B2-%D9%85%D9%85%D9%8A%D8%B2%D8%A7%D8%AA%D9%87-%D9%88%D8%B9%D9%8A%D9%88%D8%A8%D9%87-r2252/" rel="">لينكس Linux</a>، حيث يعمل كل من <a href="https://academy.hsoub.com/apps/productivity/liberoffice/libreoffice-calc/" rel="">ليبرأوفيس كالك LibreOffice Calc</a> وأوبن أوفيس كالك OpenOffice Calc بنجاح مع صيغة ملفات جداول البيانات <code>‎.xlsx</code> الخاصة بإكسل، مما يعني أن الوحدة <code>openpyxl</code> يمكن أن تعمل مع جداول البيانات الخاصة بهذين التطبيقين أيضًا، ويمكنك تنزيلهما من موقعهما الرسمي مباشرةً. قد تجد أن هذين البرنامجين أسهل في الاستخدام من إكسل بالرغم من أن برنامج إكسل مُثبَّتٌ مسبقًا على حاسوبك الشخصي، ولكن لقطات الشاشة الموجودة في هذا المقال جميعها مأخوذة من إكسل 2010 على <a href="https://academy.hsoub.com/apps/operating-systems/windows/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-windows-10-r172/" rel="">نظام تشغيل ويندوز 10</a>.
</p>

<h2 id="">
	مستندات إكسل
</h2>

<p>
	لنتعرّف أولًا على بعض التعريفات الأساسية، حيث يُسمَّى <a href="https://academy.hsoub.com/apps/productivity/office/microsoft-excel/%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-microsoft-excel-%D9%88%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D9%85%D8%B5%D9%86%D9%81-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r25/" rel="">مستند جدول بيانات إكسل بالمصنف Workbook</a>، ويُحفَظ المصنف في ملف امتداده <code>‎.xlsx</code>، ويمكن أن يحتوي المصنف على أوراق Sheets متعددة (وتسمَّى أوراق عمل Worksheets أيضًا)، كما تُسمَّى الورقة التي يعرضها المستخدم حاليًا -أو المعروضة آخر مرة قبل إغلاق إكسل- بالورقة النشطة Active Sheet.
</p>

<p>
	تحتوي كل ورقة على أعمدة Columns تتعامل معها باستخدام حروف تبدأ بالحرف A، وصفوف Rows تتعامل معها باستخدام أعداد تبدأ بالعدد 1. يسمى المربع الموجود في عمود أو صف معين بالخلية Cell، ويمكن أن تحتوي كل خلية على قيمة عددية أو نصية، وتتشكّل الورقة من شبكةٍ من الخلايا التي تحتوي على البيانات.
</p>

<h2 id="openpyxl">
	تثبيت وحدة openpyxl
</h2>

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

<p>
	سنستخدم في هذا المقال الإصدار 2.6.2 من الوحدة OpenPyXL، لذا من المهم أن تثبّت هذا الإصدار من خلال تشغيل الأمر<code>pip install --user -U openpyxl==2.6.2</code>، لأن الإصدارات الأحدث منها غير متوافقة مع المعلومات الموجودة في هذا المقال. أدخِل الأمر التالي في الصدفة التفاعلية Interactive Shell لاختبار ما إذا كان كانت وحدة OpenPyXL مُثبَّتة بصورة صحيحة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6536_8" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl</span></pre>

<p>
	إذا جرى تثبيت الوحدة بصورة صحيحة، فلن ينتج عن الأمر السابق أيّ رسائل خطأ. تذكّر استيراد الوحدة <code>openpyxl</code> قبل تشغيل أمثلة أوامر الصدفة التفاعلية في هذا المقال، وإلّا فستحصل على الخطأ <code>NameError: name 'openpyxl' is not defined</code>.
</p>

<p>
	<strong>ملاحظة</strong>: يمكنك العثور على توثيق وحدة OpenPyXL الكامل على <a href="https://openpyxl.readthedocs.io/en/stable/" rel="external nofollow">موقعها الرسمي</a>.
</p>

<h2 id="-1">
	قراءة مستندات إكسل
</h2>

<p>
	سنستخدم في الأمثلة الواردة في هذا المقال جدول بيانات اسمه <code>example.xlsx</code> مُخزَّن في المجلد الجذر، حيث يمكنك إما إنشاء جدول البيانات بنفسك أو <a href="https://nostarch.com/automatestuff2/" rel="external nofollow">تنزيله</a>. يوضّح الشكل التالي تبويبات للأوراق الافتراضية الثلاثة التي اسمها Sheet1 و Sheet2 و Sheet3 التي يوفرها إكسل تلقائيًا للمصنفات الجديدة، ولكن قد يختلف عدد هذه الأوراق الافتراضية بحسب نظام التشغيل وبرنامج جداول البيانات:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="154023" href="https://academy.hsoub.com/uploads/monthly_2024_07/01_000024.jpg.f6ad70632f9046a6169e454388ae6c59.jpg" rel=""><img alt="01 000024" class="ipsImage ipsImage_thumbnailed" data-fileid="154023" data-unique="3f9rdqwnw" src="https://academy.hsoub.com/uploads/monthly_2024_07/01_000024.jpg.f6ad70632f9046a6169e454388ae6c59.jpg"> </a>
</p>

<p style="text-align: center;">
	توجد التبويبات الخاصة بأوراق المصنف في الزاوية السفلية اليسرى من إكسل
</p>

<p>
	يجب أن تبدو الورقة 1 في مثالنا مثل الجدول التالي، ولكن إن لم تنزّل الملف <code>example.xlsx</code> من الموقع، فيجب أن تدخِل هذه البيانات في الورقة بنفسك:
</p>

<table>
	<thead>
		<tr>
			<th>
				 
			</th>
			<th>
				A
			</th>
			<th>
				B
			</th>
			<th>
				C
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				1
			</td>
			<td>
				4/5/2015 1:34:02 PM
			</td>
			<td>
				Apples
			</td>
			<td>
				73
			</td>
		</tr>
		<tr>
			<td>
				2
			</td>
			<td>
				4/5/2015 3:41:23 AM
			</td>
			<td>
				Cherries
			</td>
			<td>
				85
			</td>
		</tr>
		<tr>
			<td>
				3
			</td>
			<td>
				4/6/2015 12:46:51 PM
			</td>
			<td>
				Pears
			</td>
			<td>
				14
			</td>
		</tr>
		<tr>
			<td>
				4
			</td>
			<td>
				4/8/2015 8:59:43 AM
			</td>
			<td>
				Oranges
			</td>
			<td>
				52
			</td>
		</tr>
		<tr>
			<td>
				5
			</td>
			<td>
				4/10/2015 2:07:00 AM
			</td>
			<td>
				Apples
			</td>
			<td>
				152
			</td>
		</tr>
		<tr>
			<td>
				6
			</td>
			<td>
				4/10/2015 6:10:37 PM
			</td>
			<td>
				Bananas
			</td>
			<td>
				23
			</td>
		</tr>
		<tr>
			<td>
				7
			</td>
			<td>
				4/10/2015 2:40:46 AM
			</td>
			<td>
				Strawberries
			</td>
			<td>
				98
			</td>
		</tr>
	</tbody>
</table>

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

<h3 id="openpyxl-1">
	فتح مستندات إكسل باستخدام وحدة OpenPyXL
</h3>

<p>
	يمكنك استخدام الدالة <code>openpyxl.load_workbook()‎</code> بعد استيراد وحدة <code>openpyxl</code> مباشرةً، لذا أدخِل ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6536_10" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="pln">load_workbook</span><span class="pun">(</span><span class="str">'example.xlsx'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> type</span><span class="pun">(</span><span class="pln">wb</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="kwd">class</span><span class="pln"> </span><span class="str">'openpyxl.workbook.workbook.Workbook'</span><span class="pun">&gt;</span></pre>

<p>
	تأخذ الدالة <code>openpyxl.load_workbook()‎</code> اسم الملف وتعيد قيمة نوع بيانات المصنف <code>workbook</code>، حيث يمثل الكائن <code>Workbook</code> ملف إكسل، ويشبه ذلك كيفية تمثيل الكائن <code>File</code> ملفًا نصيًا مفتوحًا.
</p>

<p>
	تذكّر أن الملف <code>example.xlsx</code> يجب أن يكون موجودًا في مجلد العمل الحالي لتتمكّن من التعامل معه، إذ يمكنك معرفة مجلد العمل الحالي من خلال استيراد وحدة <code>os</code> واستخدام الدالة <code>os.getcwd()‎</code>، ويمكنك تغيير مجلد العمل الحالي باستخدام الدالة <code>os.chdir()‎</code>.
</p>

<h3 id="-2">
	الحصول على الأوراق من المصنف
</h3>

<p>
	يمكنك الحصول على قائمة بجميع أسماء الأوراق في المصنف من خلال الوصول إلى السمة Attribute التي هي <code>sheetnames</code>، لذا أدخِل ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6536_12" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="pln">load_workbook</span><span class="pun">(</span><span class="str">'example.xlsx'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">sheetnames </span><span class="com"># أسماء الأوراق الخاصة بالمصنف</span><span class="pln">
</span><span class="pun">[</span><span class="str">'Sheet1'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Sheet2'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Sheet3'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">[</span><span class="str">'Sheet3'</span><span class="pun">]</span><span class="pln"> </span><span class="com"># الحصول على ورقة من المصنف</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet
</span><span class="pun">&lt;</span><span class="typ">Worksheet</span><span class="pln"> </span><span class="str">"Sheet3"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> type</span><span class="pun">(</span><span class="pln">sheet</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="kwd">class</span><span class="pln"> </span><span class="str">'openpyxl.worksheet.worksheet.Worksheet'</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">title </span><span class="com"># الحصول على عنوان الورقة بوصفه سلسلة نصية</span><span class="pln">
</span><span class="str">'Sheet3'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> anotherSheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">active </span><span class="com"># الحصول على الورقة النشطة</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> anotherSheet
</span><span class="pun">&lt;</span><span class="typ">Worksheet</span><span class="pln"> </span><span class="str">"Sheet1"</span><span class="pun">&gt;</span></pre>

<p>
	يمثّل الكائنُ <code>Worksheet</code> الورقة التي يمكنك الحصول عليها باستخدام الأقواس المربعة مع السلسلة النصية التي تمثّل اسم هذه الورقة، حيث يشبه ذلك استخدام مفتاح القاموس، ويمكنك استخدام السمة <code>active</code> للكائن <code>Workbook</code> للحصول على ورقة المصنف النشطة، فالورقة النشطة هي الورقة الموجودة في المقدمة عند فتح المصنف في إكسل. كما يمكنك الحصول على اسم الكائن <code>Worksheet</code> من سمة العنوان <code>title</code> بعد الحصول على هذا الكائن.
</p>

<h3 id="-3">
	الحصول على الخلايا من الأوراق
</h3>

<p>
	يمكنك الوصول إلى الكائن <code>Cell</code> باستخدام اسمه بعد الحصول على الكائن <code>Worksheet</code>، لذا أدخِل ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6536_14" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="pln">load_workbook</span><span class="pun">(</span><span class="str">'example.xlsx'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">[</span><span class="str">'Sheet1'</span><span class="pun">]</span><span class="pln"> </span><span class="com"># الحصول على ورقة من المصنف</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'A1'</span><span class="pun">]</span><span class="pln"> </span><span class="com"># الحصول على خلية من الورقة</span><span class="pln">
</span><span class="pun">&lt;</span><span class="typ">Cell</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">.</span><span class="pln">A1</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'A1'</span><span class="pun">].</span><span class="pln">value </span><span class="com"># الحصول على القيمة من الخلية</span><span class="pln">
datetime</span><span class="pun">.</span><span class="pln">datetime</span><span class="pun">(</span><span class="lit">2015</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">13</span><span class="pun">,</span><span class="pln"> </span><span class="lit">34</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> c </span><span class="pun">=</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'B1'</span><span class="pun">]</span><span class="pln"> </span><span class="com"># الحصول على خلية أخرى من الورقة</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> c</span><span class="pun">.</span><span class="pln">value
</span><span class="str">'Apples'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="com"># الحصول على الصف والعمود والقيمة من الخلية</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Row %s, Column %s is %s'</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">c</span><span class="pun">.</span><span class="pln">row</span><span class="pun">,</span><span class="pln"> c</span><span class="pun">.</span><span class="pln">column</span><span class="pun">,</span><span class="pln"> c</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)</span><span class="pln">
</span><span class="str">'Row 1, Column B is Apples'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Cell %s is %s'</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">c</span><span class="pun">.</span><span class="pln">coordinate</span><span class="pun">,</span><span class="pln"> c</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)</span><span class="pln">
</span><span class="str">'Cell B1 is Apples'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'C1'</span><span class="pun">].</span><span class="pln">value
</span><span class="lit">73</span></pre>

<p>
	يحتوي كائن الخلية <code>Cell</code> على سمة القيمة <code>value</code> التي تحتوي على القيمة المُخزَّنة في هذه الخلية، وتحتوي الكائنات <code>Cell</code> أيضًا على سمات الصف <code>row</code> والعمود <code>column</code> والإحداثيات <code>coordinate</code> التي توفّر معلومات موقع الخلية، فمثلًا يعطينا الوصول إلى السمة <code>value</code> للكائن <code>Cell</code> الخاص بالخلية B1 السلسلة النصية <code>'Apples'</code>، وتعطينا السمة <code>row</code> العدد الصحيح 1، وتعطينا السمة <code>column</code> العمود <code>'B'</code>، وتعطي السمة <code>coordinate</code> القيمة <code>'B1'</code>.
</p>

<p>
	تفسّر الوحدة OpenPyXL تلقائيًا التواريخ الموجودة في العمود A وتعيدها بوصفها قيم <code>datetime</code> بدلًا من إعادتها <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-%D9%88%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-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r223/" rel="">كسلاسل نصية</a>، حيث سنوضّح لاحقًا نوع البيانات <code>datetime</code>.
</p>

<p>
	يمكن أن يكون تحديد عمود باستخدام حرف أمرًا صعبًا برمجيًا، وخاصةً لأن الأعمدة تبدأ باستخدام حرفين مثل AA و AB و AC بعد العمود Z، لذا يمكنك بدلًا من ذلك الحصول على خلية باستخدام التابع <code>cell()‎</code> الخاص بالورقة وتمرير أعداد صحيحة لوسطاء الكلمات المفتاحية Keyword Arguments التي هي <code>row</code> و <code>column</code> الخاصة بهذا التابع، ويكون العدد الصحيح للصف أو العمود الأول هو 1 وليس 0. لندخِل ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6536_16" style=""><span class="pln">sheet</span><span class="pun">.</span><span class="pln">cell</span><span class="pun">(</span><span class="pln">row</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">=</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="typ">Cell</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">.</span><span class="pln">B1</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">cell</span><span class="pun">(</span><span class="pln">row</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">=</span><span class="lit">2</span><span class="pun">).</span><span class="pln">value
</span><span class="str">'Apples'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</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">1</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">2</span><span class="pun">):</span><span class="pln"> </span><span class="com"># المرور على جميع الصفوف الأخرى</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">i</span><span class="pun">,</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">cell</span><span class="pun">(</span><span class="pln">row</span><span class="pun">=</span><span class="pln">i</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">=</span><span class="lit">2</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="lit">1</span><span class="pln"> </span><span class="typ">Apples</span><span class="pln">
</span><span class="lit">3</span><span class="pln"> </span><span class="typ">Pears</span><span class="pln">
</span><span class="lit">5</span><span class="pln"> </span><span class="typ">Apples</span><span class="pln">
</span><span class="lit">7</span><span class="pln"> </span><span class="typ">Strawberries</span></pre>

<p>
	لاحظ أن استخدام التابع <code>cell()‎</code> الخاص بالورقة وتمرير <code>row=1</code> و <code>column=2</code> له يعطي كائن <code>Cell</code> للخلية B1 كما فعل استخدام <code>sheet['B1']‎</code> تمامًا. يمكنك بعد ذلك كتابة <a href="https://wiki.hsoub.com/Python#for" rel="external">حلقة for</a> لطباعة قيم سلسلة من الخلايا باستخدام التابع <code>cell()‎</code> ووسطاء الكلمات المفتاحية الخاصة به.
</p>

<p>
	لنفترض أنك تريد الانتقال إلى العمود B وطباعة القيمة الموجودة في جميع الخلايا التي يكون رقم صفها عددًا فرديًا، حيث يمكنك الحصول على الخلايا لجميع الصفوف لها أرقام فردية من خلال تمرير القيمة 2 لمعامل "الخطوة step" الخاص بالدالة <code>range()‎</code>. يُمرَّر المتغير <code>i</code> الخاص بالحلقة <code>for</code> إلى وسيط الكلمة المفتاحية <code>row</code> الخاص بالتابع <code>cell()‎</code>، بينما تُمرّر القيمة 2 دائمًا إلى وسيط الكلمة المفتاحية <code>column</code> في هذه الحالة. لاحظ أننا مرّرنا العدد الصحيح 2 ولم نمرّر السلسلة النصية <code>'B'</code>.
</p>

<p>
	يمكنك تحديد حجم الورقة باستخدام السمتين <code>max_row</code> و <code>max_column</code> للكائن <code>Worksheet</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6536_18" style=""><span class="kwd">import</span><span class="pln"> openpyxl
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="pln">load_workbook</span><span class="pun">(</span><span class="str">'example.xlsx'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">[</span><span class="str">'Sheet1'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">max_row </span><span class="com"># الحصول على عدد الصفوف الأكبر</span><span class="pln">
</span><span class="lit">7</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">max_column </span><span class="com"># الحصول على عدد الأعمدة الأكبر</span><span class="pln">
</span><span class="lit">3</span></pre>

<p>
	لاحظ أن السمة <code>max_column</code> تمثل عددًا صحيحًا ولا تمثّل الحرف الذي يظهر في إكسل.
</p>

<h3 id="-4">
	تحويل حروف الأعمدة إلى أعداد
</h3>

<p>
	يمكنك تحويل أسماء الأعمدة من حروف إلى أعداد من خلال استدعاء الدالة <code>openpyxl.utils.column_index_from_string()‎</code>، ويمكنك التحويل من أعداد إلى حروف من خلال استدعاء الدالة <code>openpyxl.utils.get_column_letter()‎</code>. إذًا لندخِل ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6536_20" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="pln">utils </span><span class="kwd">import</span><span class="pln"> get_column_letter</span><span class="pun">,</span><span class="pln"> column_index_from_string
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> get_column_letter</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="com"># ترجمة العمود 1 إلى حرف</span><span class="pln">
</span><span class="str">'A'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> get_column_letter</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
</span><span class="str">'B'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> get_column_letter</span><span class="pun">(</span><span class="lit">27</span><span class="pun">)</span><span class="pln">
</span><span class="str">'AA'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> get_column_letter</span><span class="pun">(</span><span class="lit">900</span><span class="pun">)</span><span class="pln">
</span><span class="str">'AHP'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="pln">load_workbook</span><span class="pun">(</span><span class="str">'example.xlsx'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">[</span><span class="str">'Sheet1'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> get_column_letter</span><span class="pun">(</span><span class="pln">sheet</span><span class="pun">.</span><span class="pln">max_column</span><span class="pun">)</span><span class="pln">
</span><span class="str">'C'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> column_index_from_string</span><span class="pun">(</span><span class="str">'A'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># الحصول على العدد‫ المقابل للحرف A</span><span class="pln">
</span><span class="lit">1</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> column_index_from_string</span><span class="pun">(</span><span class="str">'AA'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">27</span></pre>

<p>
	يمكنك استدعاء الدالة <code>get_column_letter()‎</code> وتمرير عدد صحيح لها مثل العدد 27 لمعرفة اسم الحرف في العمود السابع والعشرين بعد استيراد الدالتين السابقتين من الوحدة <code>openpyxl.utils</code>. بينما تطبّق الدالة <code>column_index_string()‎</code> العكس، حيث تمرّر لها الحرف الذي يمثل اسم العمود، وتعطيك رقم هذا العمود. لا تحتاج إلى تحميل مصنف لاستخدام هذه الدوال، ولكن إن أردت يمكنك تحميل مصنف، ثم الحصول على الكائن <code>Worksheet</code> واستخدام سمته <code>max_column</code> مثلًا للحصول على عدد صحيح، ثم يمكنك تمرير هذا العدد الصحيح إلى الدالة <code>get_column_letter()‎</code>.
</p>

<h3 id="-5">
	الحصول على الصفوف والأعمدة من الأوراق
</h3>

<p>
	يمكنك تقسيم الكائنات <code>Worksheet</code> للحصول على كافة الكائنات <code>Cell</code> الموجودة في صف أو عمود أو منطقة مستطيلة من جدول البيانات، ثم يمكنك التكرار على جميع الخلايا الموجودة في كل قسم. أدخِل ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6536_22" style=""><span class="pln">   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="pln">load_workbook</span><span class="pun">(</span><span class="str">'example.xlsx'</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">[</span><span class="str">'Sheet1'</span><span class="pun">]</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> tuple</span><span class="pun">(</span><span class="pln">sheet</span><span class="pun">[</span><span class="str">'A1'</span><span class="pun">:</span><span class="str">'C3'</span><span class="pun">])</span><span class="pln"> </span><span class="com"># الحصول على ج‫ميع الخلايا من A1 إلى C3</span><span class="pln">
   </span><span class="pun">((&lt;</span><span class="typ">Cell</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">.</span><span class="pln">A1</span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Cell</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">.</span><span class="pln">B1</span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Cell</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">.</span><span class="pln">C1</span><span class="pun">&gt;),</span><span class="pln"> </span><span class="pun">(&lt;</span><span class="typ">Cell</span><span class="pln">
   </span><span class="str">'Sheet1'</span><span class="pun">.</span><span class="pln">A2</span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Cell</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">.</span><span class="pln">B2</span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Cell</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">.</span><span class="pln">C2</span><span class="pun">&gt;),</span><span class="pln"> </span><span class="pun">(&lt;</span><span class="typ">Cell</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">.</span><span class="pln">A3</span><span class="pun">&gt;,</span><span class="pln">
   </span><span class="pun">&lt;</span><span class="typ">Cell</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">.</span><span class="pln">B3</span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Cell</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">.</span><span class="pln">C3</span><span class="pun">&gt;))</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"> rowOfCellObjects </span><span class="kwd">in</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'A1'</span><span class="pun">:</span><span class="str">'C3'</span><span class="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"> cellObj </span><span class="kwd">in</span><span class="pln"> rowOfCellObjects</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">cellObj</span><span class="pun">.</span><span class="pln">coordinate</span><span class="pun">,</span><span class="pln"> cellObj</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">print</span><span class="pun">(</span><span class="str">'--- نهاية الصف ---'</span><span class="pun">)</span><span class="pln">

   A1 </span><span class="lit">2015</span><span class="pun">-</span><span class="lit">04</span><span class="pun">-</span><span class="lit">05</span><span class="pln"> </span><span class="lit">13</span><span class="pun">:</span><span class="lit">34</span><span class="pun">:</span><span class="lit">02</span><span class="pln">
   B1 </span><span class="typ">Apples</span><span class="pln">
   C1 </span><span class="lit">73</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">
   A2 </span><span class="lit">2015</span><span class="pun">-</span><span class="lit">04</span><span class="pun">-</span><span class="lit">05</span><span class="pln"> </span><span class="lit">03</span><span class="pun">:</span><span class="lit">41</span><span class="pun">:</span><span class="lit">23</span><span class="pln">
   B2 </span><span class="typ">Cherries</span><span class="pln">
   C2 </span><span class="lit">85</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">
   A3 </span><span class="lit">2015</span><span class="pun">-</span><span class="lit">04</span><span class="pun">-</span><span class="lit">06</span><span class="pln"> </span><span class="lit">12</span><span class="pun">:</span><span class="lit">46</span><span class="pun">:</span><span class="lit">51</span><span class="pln">
   B3 </span><span class="typ">Pears</span><span class="pln">
   C3 </span><span class="lit">14</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>Cell</code> في المنطقة المستطيلة من الخلية A1 إلى الخلية C3، وحصلنا على كائن <code>Generator</code> الذي يحتوي على كائنات <code>Cell</code> في تلك المنطقة، حيث يمكننا تصوّر الكائن <code>Generator</code> من خلال استخدام <a href="https://wiki.hsoub.com/Python/tuple" rel="external">الدالة tuple()</a><code>‎</code> معه لعرض كائنات <code>Cell</code> الخاصة به ضمن مجموعة Tuple.
</p>

<p>
	تحتوي هذه المجموعة على ثلاث مجموعات أخرى، مجموعة لكل صف من أعلى المنطقة المطلوبة إلى أسفلها، حيث تحتوي كل مجموعة من هذه المجموعات الداخلية الثلاث على كائنات <code>Cell</code> في صف واحد من المنطقة المطلوبة من الخلية الموجودة في أقصى اليسار إلى اليمين. يحتوي قسم الورقة الذي حدّدناه على جميع كائنات <code>Cell</code> في المنطقة المؤلفة من الخلية A1 إلى الخلية C3، بدءًا من الخلية العلوية اليسرى وانتهاءً بالخلية السفلية اليمنى. طبعنا قيم كل خلية في هذه المنطقة باستخدام حلقتي <code>for</code>، حيث تتكرر حلقة <code>for</code> الخارجية على كل صف في القسم ➊، ثم تتكرر حلقة <code>for</code> المتداخلة لكل صف على كل خلية في هذا الصف ➋.
</p>

<p>
	يمكن أيضًا الوصول إلى قيم الخلايا في صف أو عمود معين من خلال استخدام سمة <code>rows</code> و <code>columns</code> الخاصة بكائن <code>Worksheet</code>، ولكن يجب تحويل هذه السمات إلى قوائم باستخدام الدالة <code>list()‎</code> قبل أن تتمكّن من استخدام الأقواس المربعة والفهرس معها. إذًا لندخِل ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6536_24" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="pln">load_workbook</span><span class="pun">(</span><span class="str">'example.xlsx'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">.</span><span class="pln">active
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">sheet</span><span class="pun">.</span><span class="pln">columns</span><span class="pun">)[</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="com"># الحصول على خلايا العمود الثاني</span><span class="pln">
</span><span class="pun">(&lt;</span><span class="typ">Cell</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">.</span><span class="pln">B1</span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Cell</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">.</span><span class="pln">B2</span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Cell</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">.</span><span class="pln">B3</span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Cell</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">.</span><span class="pln">
B4</span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Cell</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">.</span><span class="pln">B5</span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Cell</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">.</span><span class="pln">B6</span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Cell</span><span class="pln"> </span><span class="str">'Sheet1'</span><span class="pun">.</span><span class="pln">B7</span><span class="pun">&gt;)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> cellObj </span><span class="kwd">in</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">sheet</span><span class="pun">.</span><span class="pln">columns</span><span class="pun">)[</span><span class="lit">1</span><span class="pun">]:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">cellObj</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)</span><span class="pln">

</span><span class="typ">Apples</span><span class="pln">
</span><span class="typ">Cherries</span><span class="pln">
</span><span class="typ">Pears</span><span class="pln">
</span><span class="typ">Oranges</span><span class="pln">
</span><span class="typ">Apples</span><span class="pln">
</span><span class="typ">Bananas</span><span class="pln">
</span><span class="typ">Strawberries</span></pre>

<p>
	سيؤدي استخدام السمة <code>rows</code> مع الكائن <code>Worksheet</code> إلى إعطاء مجموعة من عدة مجموعات، وتمثل كل مجموعة من هذه المجموعات الداخلية صفًا، وتحتوي على كائنات <code>Cell</code> الموجودة في هذا الصف. تعطي السمة <code>columns</code> أيضًا مجموعة من عدة مجموعات، حيث تحتوي كل مجموعة من المجموعات الداخلية على كائنات <code>Cell</code> في عمود معين. لدينا في مثالنا الملف <code>example.xlsx</code> الذي يحتوي على 7 صفوف و3 أعمدة، وبالتالي تعطي السمة <code>rows</code> مجموعة مؤلفةً من 7 مجموعات، حيث تحتوي كل منها على 3 كائنات <code>Cell</code>، وتعطي السمة <code>columns</code> مجموعة مكونة من 3 مجموعات، حيث تحتوي كل منها على 7 كائنات <code>Cell</code>.
</p>

<p>
	يمكن الوصول إلى مجموعة معينة من خلال الإشارة إليها باستخدام فهرسها في المجموعة الكبرى، فمثلًا نحصل على المجموعة التي تمثل العمود B من خلال استخدام <code>list(sheet.columns)[1]‎</code>، ونحصل على المجموعة التي تحتوي على كائنات <code>Cell</code> في العمود A من خلال استخدام <code>list(sheet.columns)[0]‎</code>. يمكنك بعد أن يكون لديك مجموعة تمثل صفًا أو عمودًا واحدًا التكرار على كائنات <code>Cell</code> الخاصة بها وطباعة قيمها.
</p>

<h3 id="-6">
	المصنفات والأوراق والخلايا
</h3>

<p>
	إليك ملخص بجميع الدوال والتوابع وأنواع البيانات المستخدمة في قراءة خلية من ملف جدول بيانات:
</p>

<ol>
	<li>
		استيراد وحدة <code>openpyxl</code>.
	</li>
	<li>
		استدعاء الدالة <code>openpyxl.load_workbook()‎</code>.
	</li>
	<li>
		الحصول على كائن <code>Workbook</code>.
	</li>
	<li>
		استخدام السمة <code>active</code> أو السمة <code>sheetnames</code>.
	</li>
	<li>
		الحصول على كائن <code>Worksheet</code>.
	</li>
	<li>
		استخدم طريقة الفهرسة أو تابع <code>cell()‎</code> الخاص بالورقة مع وسطاء الكلمات المفتاحية <code>row</code> و <code>column</code>.
	</li>
	<li>
		الحصول على كائن <code>Cell</code>.
	</li>
	<li>
		قراءة السمة <code>value</code> الخاصة بالكائن <code>Cell</code>.
	</li>
</ol>

<h2 id="-7">
	تطبيق عملي: قراءة البيانات من جدول بيانات
</h2>

<p>
	لنفترض أن لديك جدول بيانات يمثّل الإحصاء السكاني للولايات المتحدة الأمريكية لعام 2010، ولديك مهمة مملة تتمثل في استعراض آلاف الصفوف لحساب إجمالي عدد السكان وعدد المناطق الإحصائية Census Tracts لكل مقاطعة County، فالمنطقة الإحصائية هي ببساطة منطقة جغرافية محددة لأغراض الإحصاء السكاني، ويمثل كل صف في جدول البيانات منطقةً إحصائية واحدة. سنسمّي ملف جدول البيانات <code>censuspopdata.xlsx</code> الذي يمكنك <a href="https://nostarch.com/automatestuff2/" rel="external nofollow">تنزيله</a>، وتبدو محتوياته كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="154022" href="https://academy.hsoub.com/uploads/monthly_2024_07/02_000116.jpg.bd3c28d887fe07329d8da6142b211ef7.jpg" rel=""><img alt="02 000116" class="ipsImage ipsImage_thumbnailed" data-fileid="154022" data-unique="o11ayfqf7" src="https://academy.hsoub.com/uploads/monthly_2024_07/02_000116.jpg.bd3c28d887fe07329d8da6142b211ef7.jpg"> </a>
</p>

<p style="text-align: center;">
	جدول بيانات censuspopdata.xlsx
</p>

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

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

<ol>
	<li>
		يقرأ البيانات من جدول بيانات إكسل.
	</li>
	<li>
		يحسب عدد المناطق الإحصائية في كل مقاطعة.
	</li>
	<li>
		يحسب إجمالي عدد السكان في كل مقاطعة.
	</li>
	<li>
		يطبع النتائج.
	</li>
</ol>

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

<ol>
	<li>
		فتح وقراءة خلايا مستند إكسل باستخدام وحدة <code>openpyxl</code>.
	</li>
	<li>
		حساب جميع بيانات المناطق الإحصائية وعدد السكان وتخزينها في هيكل بيانات.
	</li>
	<li>
		كتابة هيكل البيانات في ملف نصي له الامتداد <code>‎.py</code> باستخدام الوحدة <code>pprint</code>.
	</li>
</ol>

<h3 id="-8">
	الخطوة الأولى: قراءة بيانات جدول البيانات
</h3>

<p>
	توجد ورقة واحدة فقط في جدول البيانات <code>censuspopdata.xlsx</code>، تسمى "عدد السكان حسب المنطقة الإحصائية" <code>'Population by Census Tract'</code>، ويحتوي كل صف على بيانات منطقة إحصائية واحدة، والأعمدة هي رقم المنطقة (A) واختصار الولاية (B) واسم المقاطعة (C) وعدد سكان المنطقة (D).
</p>

<p>
	افتح تبويبًا جديدًا لإنشاء ملف جديد في محرّرك وأدخِل الشيفرة البرمجية التالية، واحفظ الملف بالاسم <code>readCensusExcel.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6536_26" style=""><span class="com">#! python3</span><span class="pln">
   </span><span class="com"># readCensusExcel.py - جدول عدد السكان وعدد المناطق الإحصائية لكل مقاطعة</span><span class="pln">

</span><span class="pun">➊</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> openpyxl</span><span class="pun">,</span><span class="pln"> pprint
   </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Opening workbook...'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">➋</span><span class="pln"> wb </span><span class="pun">=</span><span class="pln"> openpyxl</span><span class="pun">.</span><span class="pln">load_workbook</span><span class="pun">(</span><span class="str">'censuspopdata.xlsx'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">➌</span><span class="pln"> sheet </span><span class="pun">=</span><span class="pln"> wb</span><span class="pun">[</span><span class="str">'Population by Census Tract'</span><span class="pun">]</span><span class="pln">
   countyData </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">

   </span><span class="com"># املأ بي‫انات المقاطعة countyData بعدد سكان كل مقاطعة ومناطقها الإحصائية</span><span class="pln">
   </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Reading rows...'</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"> row </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">max_row </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">):</span><span class="pln">
       </span><span class="com"># يحتوي كل صف في جدول البيانات على بياناتٍ لمنطقة إحصائية واحدة</span><span class="pln">
       state  </span><span class="pun">=</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'B'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">row</span><span class="pun">)].</span><span class="pln">value
       county </span><span class="pun">=</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'C'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">row</span><span class="pun">)].</span><span class="pln">value
       pop    </span><span class="pun">=</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'D'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">row</span><span class="pun">)].</span><span class="pln">value

</span><span class="com"># افتح ملفًا نص‫يًا جديدًا واكتب محتويات بيانات المقاطعة countyData فيه</span></pre>

<p>
	تستورد الشيفرة البرمجية السابقة الوحدة <code>openpyxl</code> و<a href="https://wiki.hsoub.com/Python/pprint" rel="external">الوحدة pprint</a> التي ستستخدمها لطباعة بيانات المقاطعة النهائية ➊، ثم تفتح الملف <code>censuspopdata.xlsx</code> ➋، وتحصل على الورقة التي تحتوي على البيانات الإحصائية ➌، وتبدأ بالتكرار على صفوف هذه الورقة ➍.
</p>

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

<h3 id="-9">
	الخطوة الثانية: ملء هيكل البيانات
</h3>

<p>
	يُعَد هيكل البيانات المُخزَّن في المتغير <code>countyData</code> قاموسًا تكون اختصارات أسماء الولايات مفاتيحًا له، حيث سيُربَط اختصار كل ولاية مع قاموس آخر مفاتيحه هي <a href="https://wiki.hsoub.com/Python/str" rel="external">سلاسل نصية</a> تمثّل أسماء المقاطعات في تلك الولاية، وسيُربَط كل اسم مقاطعة بدوره مع قاموسٍ آخر يحتوي على مفتاحين فقط هما <code>'tracts'</code> و <code>'pop'</code>، ويُربَط هذان المفتاحان مع عدد المناطق الإحصائية وعدد السكان في المقاطعة، فمثلًا سيبدو القاموس مشابهًا لما يلي:
</p>

<pre class="ipsCode">{'AK': {'Aleutians East': {'pop': 3141, 'tracts': 1},
        'Aleutians West': {'pop': 5561, 'tracts': 2},
        'Anchorage': {'pop': 291826, 'tracts': 55},
        'Bethel': {'pop': 17013, 'tracts': 3},
        'Bristol Bay': {'pop': 997, 'tracts': 1},
        --snip–
</pre>

<p>
	إذا خُزِّن القاموس السابق في المتغير <code>countyData</code>، فيمكن تقييم التعابير التالية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6536_29" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> countyData</span><span class="pun">[</span><span class="str">'AK'</span><span class="pun">][</span><span class="str">'Anchorage'</span><span class="pun">][</span><span class="str">'pop'</span><span class="pun">]</span><span class="pln">
</span><span class="lit">291826</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> countyData</span><span class="pun">[</span><span class="str">'AK'</span><span class="pun">][</span><span class="str">'Anchorage'</span><span class="pun">][</span><span class="str">'tracts'</span><span class="pun">]</span><span class="pln">
</span><span class="lit">55</span></pre>

<p>
	وستكون مفاتيح قاموس <code>countyData</code> كما يلي:
</p>

<pre class="ipsCode">countyData[state abbrev][county]['tracts']
countyData[state abbrev][county]['pop']
</pre>

<p>
	عرفتَ كيفية تنظيم هيكل بيانات <code>countyData</code>، ويمكنك الآن كتابة الشيفرة البرمجية التي ستملؤه ببيانات المقاطعة، لذا أضِف الشيفرة البرمجية التالية إلى نهاية برنامجك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6536_31" style=""><span class="com">#! python 3</span><span class="pln">
</span><span class="com"># readCensusExcel.py - جدول عدد السكان وعدد المناطق الإحصائية لكل مقاطعة</span><span class="pln">

</span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> row </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">max_row </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">):</span><span class="pln">
     </span><span class="com"># يحتوي كل صف في جدول البيانات على بيانات لمنطقة إحصائية واحدة</span><span class="pln">
     state  </span><span class="pun">=</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'B'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">row</span><span class="pun">)].</span><span class="pln">value
     county </span><span class="pun">=</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'C'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">row</span><span class="pun">)].</span><span class="pln">value
     pop    </span><span class="pun">=</span><span class="pln"> sheet</span><span class="pun">[</span><span class="str">'D'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">row</span><span class="pun">)].</span><span class="pln">value

     </span><span class="com"># تأكد من ‫وجود مفتاح هذه الولاية state</span><span class="pln">
  </span><span class="pun">➊</span><span class="pln"> countyData</span><span class="pun">.</span><span class="pln">setdefault</span><span class="pun">(</span><span class="pln">state</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{})</span><span class="pln">
     </span><span class="com"># تأكد ‫من وجود مفتاح هذه المقاطعة county في تلك الولاية</span><span class="pln">
  </span><span class="pun">➋</span><span class="pln"> countyData</span><span class="pun">[</span><span class="pln">state</span><span class="pun">].</span><span class="pln">setdefault</span><span class="pun">(</span><span class="pln">county</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="str">'tracts'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="str">'pop'</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"># يمثل كل صف منطقة إحصائية واحدة، لذا يجب زيادة عدد المناطق بمقدار واحد</span><span class="pln">
  </span><span class="pun">➌</span><span class="pln"> countyData</span><span class="pun">[</span><span class="pln">state</span><span class="pun">][</span><span class="pln">county</span><span class="pun">][</span><span class="str">'tracts'</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="com"># زي‫ادة عدد سكان pop المقاطعة بمقدار عدد السكان في هذه المنطقة الإحصائية</span><span class="pln">
  </span><span class="pun">➍</span><span class="pln"> countyData</span><span class="pun">[</span><span class="pln">state</span><span class="pun">][</span><span class="pln">county</span><span class="pun">][</span><span class="str">'pop'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+=</span><span class="pln"> int</span><span class="pun">(</span><span class="pln">pop</span><span class="pun">)</span><span class="pln">

</span><span class="com"># افتح ملفًا نص‫يًا جديدًا واكتب محتويات بيانات المقاطعة countyData فيه</span></pre>

<p>
	يجري السطران الأخيران من الشيفرة البرمجية السابقة العمليات الحسابية الفعلية، حيث تزيد قيمة المناطق الإحصائية <code>tracts</code> ➌ وقيمة عدد السكان <code>pop</code> ➍ للمقاطعة الحالية في كل تكرار لحلقة <code>for</code>. بينما سببُ وجود الشيفرة البرمجية المتبقية هو أنه لا يمكنك إضافة قاموس المقاطعة بوصفه قيمةً لمفتاح اختصار الولاية إلّا عند وجود المفتاح نفسه في <code>countyData</code>، إذ ستتسبّب التعليمة <code>countyData['AK']['Anchorage']['tracts'] += 1</code> في حدوث خطأ إن لم يكن المفتاح <code>'AK'</code> موجودًا بعد. يمكنك التأكد من وجود مفتاح اختصار الولاية في هيكل بياناتك من خلال استدعاء التابع <code>setdefault()‎</code> لضبط قيمة الولاية <code>state</code> ➊ إن لم تكن موجودة مسبقًا.
</p>

<p>
	يحتاج قاموس <code>countyData</code> إلى قاموس آخر بوصفه قيمةً لكل مفتاح يمثّل اختصار الولاية، وبالتالي سيحتاج كلٌّ من هذه القواميس إلى قاموس خاص به بوصفه قيمة لكل مفتاح مقاطعة ➋، وسيحتاج كل من هذه القواميس بدوره إلى مفاتيح <code>'tracts'</code> و <code>'pop'</code> التي تبدأ بالقيمة الصحيحة 0. إذا شعرت بالضياع عند تتبّع بنية القاموس، فارجع إلى مثال القاموس في بداية هذه الفقرة.
</p>

<p>
	لن يفعل التابع <code>setdefault()‎</code> شيئًا إذا كان المفتاح موجودًا مسبقًا، وبالتالي يمكنك استدعاؤه في كل تكرار للحلقة <code>for</code> بدون مشاكل.
</p>

<h3 id="-10">
	الخطوة الثالثة: كتابة النتائج في ملف
</h3>

<p>
	سيحتوي قاموس <code>countyData</code> بعد انتهاء حلقة <code>for</code> على جميع معلومات عدد السكان والمناطق المرتبطة بمفتاح المقاطعة county والولاية state، ويمكنك عندها برمجة مزيدٍ من الشيفرة البرمجية لكتابة هذه المعلومات في ملف نصي أو جدول بيانات إكسل آخر. لنستخدم الآن الدالة <code>pprint.pformat()‎</code> لكتابة قيمة قاموس <code>countyData</code> بوصفها سلسلة نصية ضخمة في ملف اسمه <code>census2010.py</code>، لذا أضِف الشيفرة البرمجية التالية إلى نهاية برنامجك، وتأكد من إبقائه بدون مسافة بادئة بحيث يبقى خارج حلقة <code>for</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6536_33" style=""><span class="com">#! python 3</span><span class="pln">
</span><span class="com"># readCensusExcel.py - جدول عدد السكان وعدد المناطق الإحصائية لكل مقاطعة</span><span class="pln">

</span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> row </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> sheet</span><span class="pun">.</span><span class="pln">max_row </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">snip</span><span class="pun">--</span><span class="pln">

</span><span class="com"># افتح ملفًا نص‫يًا جديدًا واكتب محتويات بيانات المقاطعة countyData فيه</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Writing results...'</span><span class="pun">)</span><span class="pln">
resultFile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'census2010.py'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'w'</span><span class="pun">)</span><span class="pln">
resultFile</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">'allData = '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> pprint</span><span class="pun">.</span><span class="pln">pformat</span><span class="pun">(</span><span class="pln">countyData</span><span class="pun">))</span><span class="pln">
resultFile</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="str">'Done.'</span><span class="pun">)</span></pre>

<p>
	ينتج عن الدالة pprint.pformat()<code>‎</code> سلسلةٌ نصية مُنسَّقة كشيفرة بايثون صالحة، والتي يمكنك إخراجها إلى ملف نصي اسمه <code>census2010.py</code>، وبالتالي سيتولد برنامج بايثون من برنامج بايثون الخاص بك. قد يبدو ذلك معقدًا، ولكن تتمثّل الفائدة في أنه يمكنك استيراد الملف <code>census2010.py</code> مثل أي وحدة بايثون أخرى. غيّر مجلد العمل الحالي إلى المجلد الذي يحتوي على الملف <code>census2010.py</code> ثم استورده في الصدفة التفاعلية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6536_35" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> os
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> census2010
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> census2010</span><span class="pun">.</span><span class="pln">allData</span><span class="pun">[</span><span class="str">'AK'</span><span class="pun">][</span><span class="str">'Anchorage'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">{</span><span class="str">'pop'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">291826</span><span class="pun">,</span><span class="pln"> </span><span class="str">'tracts'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">55</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> anchoragePop </span><span class="pun">=</span><span class="pln"> census2010</span><span class="pun">.</span><span class="pln">allData</span><span class="pun">[</span><span class="str">'AK'</span><span class="pun">][</span><span class="str">'Anchorage'</span><span class="pun">][</span><span class="str">'pop'</span><span class="pun">]</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="str">'The 2010 population of Anchorage was '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">anchoragePop</span><span class="pun">))</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> </span><span class="lit">2010</span><span class="pln"> population of </span><span class="typ">Anchorage</span><span class="pln"> was </span><span class="lit">291826</span></pre>

<p>
	يُعَد برنامج <code>readCensusExcel.py</code> عديم الجدوى، فلا حاجة لتشغيله مرة أخرى بعد حفظ نتائجه في الملف <code>census2010.py</code>، ويمكنك تشغيل الأمر <code>import census2010</code> عندما تحتاج إلى بيانات المقاطعة.
</p>

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

<p>
	<strong>ملاحظة</strong>: لا تنسَ أنه يمكنك <a href="https://nostarch.com/automatestuff2/" rel="external nofollow">تنزيل</a> البرنامج الكامل.
</p>

<h3 id="-11">
	أفكار لبرامج مماثلة
</h3>

<p>
	تستخدم العديد من الشركات والمكاتب برنامج إكسل لتخزين أنواع مختلفة من البيانات، وتصبح جداول البيانات كبيرة الحجم وغير عملية بسهولة. تمتلك البرامج التي تحلّل جدول بيانات إكسل بنية مماثلة، فهي تحمّل ملف جدول البيانات، وتجهّز بعض المتغيرات أو <a href="https://academy.hsoub.com/programming/general/%D9%87%D9%8A%D8%A7%D9%83%D9%84-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-data-structures/" rel="">هياكل البيانات</a>، ثم تتكرر على كل صف من الصفوف في جدول البيانات، حيث يمكن أن تفعل مثل هذه البرامج ما يلي:
</p>

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

<h2 id="-12">
	الخلاصة
</h2>

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

<p>
	ترجمة -وبتصرُّف- للقسم Reading Excel Documents من مقال <a href="https://automatetheboringstuff.com/2e/chapter13/" rel="external nofollow">Working with Excel Spreadsheets</a> لصاحبه Al Sweigart.
</p>

<h2 id="-13">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/python/%D8%A7%D8%B3%D8%AA%D8%AE%D8%B1%D8%A7%D8%AC-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%85%D9%86-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%B9%D8%A8%D8%B1-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2366/" rel="">استخراج البيانات من الويب عبر لغة بايثون Python</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D9%82%D8%B1%D8%A7%D8%A1%D8%A9-%D9%88%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%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-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2347/" rel="">قراءة وكتابة الملفات باستخدام لغة بايثون Python</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%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%88%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1858/" rel="">التعامل مع الملفات والمسارات في بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%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%85%D9%84%D9%81%D8%A7%D8%AA-%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-r484/" rel="">كيفية التعامل مع الملفات النصية في بايثون 3</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/apps/productivity/office/microsoft-excel/%D9%86%D8%B8%D8%B1%D8%A9-%D8%B9%D8%A7%D9%85%D8%A9-%D8%B9%D9%84%D9%89-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D8%AC-%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-microsoft-excel-r930/" rel="">نظرة عامة على برنامج مايكروسوفت إكسل Microsoft Excel</a>
	</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>
</ul>
]]></description><guid isPermaLink="false">2374</guid><pubDate>Wed, 24 Jul 2024 15:01:06 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x62E;&#x631;&#x627;&#x62C; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x645;&#x646; &#x627;&#x644;&#x648;&#x64A;&#x628; &#x639;&#x628;&#x631; &#x644;&#x63A;&#x629; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646; Python</title><link>https://academy.hsoub.com/programming/python/%D8%A7%D8%B3%D8%AA%D8%AE%D8%B1%D8%A7%D8%AC-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%85%D9%86-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%B9%D8%A8%D8%B1-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2366/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_07/------.png.0ad67a3fc6772ecb1bf2c7889d87fee7.png" /></p>
<p>
	كانت لحظة مرعبة حينما جلست على حاسوبي بعد أن «عضّ القرش» كبل الإنترنت وانقطع، وأدركت حينها كم أقضي وقتًا على الإنترنت حينما أستعمل حاسوبي؛ فلدي عادة أن أتحقق من بريدي يدويًا (مع أن التنبيهات تصلني أولًا بأول!) وأفتح تويتر (إكس، سمهِّ ما شئت) وأنظر ما آخر المستجدات.
</p>

<p>
	كثيرٌ من عملنا على الحاسوب يتطلب وصولًا إلى الانترنت، ومصطلح «استخراج البيانات من الويب» Web scraping يستعمل مع البرامج التي تنزل المحتوى من الإنترنت وتعالجه. فمثلًا لدى غوغل عدد من البوتات لتنزيل محتوى صفحات الويب وفهرستها وأرشفتها لتستعملها في محرك البحث.
</p>

<p>
	سنتعلم في هذا المقال عن عددٍ من <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-modules-%D9%88%D8%A7%D9%84%D8%AD%D8%B2%D9%85-packages-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r329/" rel="">الوحدات في بايثون</a> التي تسهل علينا استخراج البيانات من الويب:
</p>

<ul>
	<li>
		<code>webbrowser</code>: حزمة تأتي مع <a href="https://academy.hsoub.com/programming/python/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r211/" rel="">بايثون</a> وتفتح متصفحًا على صفحة ويب معينة.
	</li>
	<li>
		<code>requests</code>: تنزل الملفات وصفحات الويب من الإنترنت.
	</li>
	<li>
		<code>bs4</code>: تفسّر شيفرات <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> التي تكتب فيها <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8%D8%9F-r2094/" rel="">صفحات الويب</a>.
	</li>
	<li>
		<code>selenium</code>: تشغل وتتحمل في متصفح ويب، والوحدة <code>selenium</code> قادرة على ملء الاستمارات ومحاكاة ضغطات الفأرة في المتصفح.
	</li>
</ul>

<h2 id="mapitpywebbrowser">
	مشروع: برنامج mapIt.py مع وحدة webbrowser
</h2>

<p>
	الدالة <code>open()‎</code> في الوحدة <code>webbrowser</code> تفتح صفحة ويب معينة في نافذة متصفح جديدة. جرب ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9154_10" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> webbrowser
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> webbrowser</span><span class="pun">.</span><span class="pln">open</span><span class="pun">(</span><span class="str">'https://academy.hsoub.com/'</span><span class="pun">)</span></pre>

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

<p>
	هذا ما يفعله البرنامج: يحصل على عنوان الشارع من وسائط <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%A7-%D9%87%D9%88-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%9F-r353/" rel="">سطر الأوامر</a> أو من الحافظة يفتح نافذة متصفح ويوجهها إلى صفحة خرائط جوجل المرتبطة بعنوان الشارع.
</p>

<p>
	هذا يعني أن على <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> أن تفعل ما يلي: تقرأ وسائط سطر الأوامر تقرأ محتويات الحافظة تستدعي الدالة <code>webbrowser.open()‎</code> لتفتح صفحة الويب.
</p>

<p>
	احفظ ملفًا جديدًا باسم <code>mapIt.py</code>، ولنبدأ برمجته.
</p>

<h3 id="1">
	الخطوة 1: معرفة الرابط الصحيح
</h3>

<p>
	اعتمادًا على التعليمات الموجودة في الملحق ب، اضبط برنامج <code>mapIt.py</code> ليعمل من سطر الأوامر كما في المثال الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9154_13" style=""><span class="pln">C</span><span class="pun">:</span><span class="pln">\&gt; mapit </span><span class="lit">870</span><span class="pln"> </span><span class="typ">Valencia</span><span class="pln"> </span><span class="typ">St</span><span class="pun">,</span><span class="pln"> </span><span class="typ">San</span><span class="pln"> </span><span class="typ">Francisco</span><span class="pun">,</span><span class="pln"> CA </span><span class="lit">94110</span></pre>

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

<p>
	علينا بدايةً أن نحصِّل ما هو <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/" rel="">عنوان URL</a> الذي يجب فتحه للعثور على شارع معين. إذا فتحت <a href="https://maps.google.com/" rel="external nofollow">خرائط جوجل</a> في المتصفح وبحثت عن عنوان فسيكون الرابط في الشريط العلوي يشبه:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9154_21" style=""><span class="pln">https</span><span class="pun">://</span><span class="pln">www</span><span class="pun">.</span><span class="pln">google</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">maps</span><span class="pun">/</span><span class="pln">place</span><span class="pun">/</span><span class="lit">870</span><span class="pun">+</span><span class="typ">Valencia</span><span class="pun">+</span><span class="typ">St</span><span class="pun">/@</span><span class="lit">37.7590311</span><span class="pun">,-</span><span class="lit">122.4215096</span><span class="pun">,</span><span class="lit">17z</span><span class="pun">/</span><span class="pln">data</span><span class="pun">=!</span><span class="lit">3m1</span><span class="pun">!</span><span class="lit">4b1</span><span class="pun">!</span><span class="lit">4m2</span><span class="pun">!</span><span class="lit">3m1</span><span class="pun">!</span><span class="lit">1s0x808f7e3dadc07a37</span><span class="pun">:</span><span class="lit">0xc86b0b2bb93b73d8</span></pre>

<p>
	نعم العنوان في الرابط، لكن هنالك نص كثير إضافي غيره.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9154_23" style=""><span class="pln"> https</span><span class="pun">://</span><span class="pln">www</span><span class="pun">.</span><span class="pln">google</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">maps</span><span class="pun">/</span><span class="pln">place</span><span class="pun">/</span><span class="lit">870</span><span class="pun">+</span><span class="typ">Valencia</span><span class="pun">+</span><span class="typ">St</span><span class="pun">+</span><span class="typ">San</span><span class="pun">+</span><span class="typ">Francisco</span><span class="pun">+</span><span class="pln">CA</span><span class="pun">/</span><span class="pln"> </span></pre>

<p>
	فسترى العنوان مفتوحًا أمامك. وبهذا كل ما نحتاج إليه هو فتح صفحة ويب ذات العنوان التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9154_27" style=""><span class="pln"> https</span><span class="pun">://</span><span class="pln">www</span><span class="pun">.</span><span class="pln">google</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">maps</span><span class="pun">/</span><span class="pln">place</span><span class="pun">/</span><span class="pln">your_address_string</span></pre>

<p>
	حيث your_address_string هو العنوان الذي تريد عرضه في الخريطة.
</p>

<h3 id="2">
	الخطوة 2: التعامل مع وسائط سطر الأوامر
</h3>

<p>
	يجب أن تبدو الشيفرة لديك كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9154_29" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># mapIt.py - تشغيل خريطة في المتصفح باستخدام عنوان</span><span class="pln">
</span><span class="com"># من سطر الأوامر أو الحافظة.</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> webbrowser</span><span class="pun">,</span><span class="pln"> sys
</span><span class="kwd">if</span><span class="pln"> len</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="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
    </span><span class="com"># Get address from command line.</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">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="com"># TODO: الحصول على العنوان من الحافظة.</span></pre>

<p>
	بعد سطر !# سنستورد <a href="https://wiki.hsoub.com/Python/webbrowser" rel="external">الوحدة webbrowser</a> لتشغيل المتصفح والوحدة <code>sys</code> لمحاولة قراءة وسائط سطر الأوامر.
</p>

<p>
	يخزن المتغير <code>sys.argv</code> اسم الملف ووسائط سطر الأوامر، وإذا احتوت هذه القائمة على أكثر من عنصر واحد (الذي هو اسم الملف) فيجب أن تكون قيمة استدعاء <code>len(sys.argv)‎</code> أكبر من 1، وهذا يعني أن هنالك وسائط في سطر الأوامر.
</p>

<p>
	عادةً ما يُفصَل بين وسائط سطر الأوامر بفراغات، لكن في هذه الحالة نريد أن نفسر جميع الوسائط على أنها سلسلة نصية واحدة، ولما كانت قيمة <code>sys.argv</code> هي قائمة تحتوي على <a href="https://wiki.hsoub.com/Python/str" rel="external">سلاسل نصية</a>، فيمكننا استخدام التابع <code>join()‎</code> معها، مما يعيد سلسلة نصية واحدة؛ لكن انتبه أننا لا نريد اسم الملف ضمن تلك السلسلة النصية، فعلينا استخدام <code>sys.arv[1:]‎</code> لإزالة أول عنصر في القائمة، ثم سنتخزن تلك القيمة في المتغير <code>address</code>.
</p>

<p>
	يمكنك تشغيل البرنامج بكتابة ما يلي في سطر الأوامر:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9154_31" style=""><span class="pln">mapit </span><span class="lit">870</span><span class="pln"> </span><span class="typ">Valencia</span><span class="pln"> </span><span class="typ">St</span><span class="pun">,</span><span class="pln"> </span><span class="typ">San</span><span class="pln"> </span><span class="typ">Francisco</span><span class="pun">,</span><span class="pln"> CA </span><span class="lit">94110</span></pre>

<p>
	وستكون قيمة المتغير <code>sys.argv</code> هي القائمة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9154_33" style=""><span class="pun">[</span><span class="str">'mapIt.py'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'870'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Valencia'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'St, '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'San'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Francisco, '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'CA'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'94110'</span><span class="pun">]</span></pre>

<p>
	وبالتالي تكون قيمة المتغير <code>address</code> هي السلسلة النصية <code>'870 Valencia St, San Francisco, CA 94110'</code>.
</p>

<h3 id="3">
	الخطوة 3: التعامل مع محتويات الحافظة وتشغيل المتصفح
</h3>

<p>
	تأكد أن الشيفرة الخاصة بك تشبه الشيفرة الآتية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9154_35" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># mapIt.py - تشغيل خريطة في المتصفح باستخدام عنوان</span><span class="pln">
</span><span class="com"># من سطر الأوامر أو الحافظة.</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> webbrowser</span><span class="pun">,</span><span class="pln"> sys</span><span class="pun">,</span><span class="pln"> pyperclip
</span><span class="kwd">if</span><span class="pln"> len</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="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
    </span><span class="com"># Get address from command line.</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">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="kwd">else</span><span class="pun">:</span><span class="pln">
    </span><span class="com"># الحصول على العنوان من الحافظة.</span><span class="pln">
    address </span><span class="pun">=</span><span class="pln"> pyperclip</span><span class="pun">.</span><span class="pln">paste</span><span class="pun">()</span><span class="pln">

webbrowser</span><span class="pun">.</span><span class="pln">open</span><span class="pun">(</span><span class="str">'https://www.google.com/maps/place/'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> address</span><span class="pun">)</span></pre>

<p>
	إذا لم تكن هنالك وسائط ممررة عبر سطر الأوامر، فسيفترض البرنامج أن العنوان منسوخ إلى الحافظة، ويمكننا الحصول على محتوى الحافظة باستخدام <code>pyperclip.paste()‎</code> وتخزينها في المتغير <code>address</code>. آخر خطوة هي تشغيل المتصفح مع توفير <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/" rel="">رابط URL</a> صحيح لخرائط غوغل عبر <code>webbrowser.open()‎</code>.
</p>

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

<table>
	<thead>
		<tr>
			<th>
				فتح الخريطة يدويًا
			</th>
			<th>
				استخدام سكربت <code>mapIt.py</code>
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				<p>
					تحديد العنوان
				</p>

				<p>
					نسخ العنوان
				</p>

				<p>
					فتح متصفح الويب
				</p>

				<p>
					الذهاب إلى خرائط غوغل
				</p>

				<p>
					الضغط على حقل الإدخال
				</p>

				<p>
					لصق العنوان الضغط على enter
				</p>
			</td>
			<td>
				<p>
					تحديد العنوان
				</p>

				<p>
					نسخ العنوان
				</p>

				<p>
					تشغيل <code>mapIt.py</code>
				</p>
			</td>
		</tr>
	</tbody>
</table>

<p style="text-align: center;">
	مقارنة الخطوات اللازمة لعرض الخريطة
</p>

<h3 id="">
	أفكار لبرامج مشابهة
</h3>

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

<ul>
	<li>
		برنامج يفتح جميع الروابط المذكورة في مستند نصي في ألسنة جديدة.
	</li>
	<li>
		برنامج يفتح المتصفح على صفحة الطقس لمدينتك.
	</li>
	<li>
		برنامج يفتح <a href="https://academy.hsoub.com/marketing/social-media/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D9%88%D8%B3%D8%A7%D8%A6%D9%84-%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%B5%D9%84-%D8%A7%D9%84%D8%A7%D8%AC%D8%AA%D9%85%D8%A7%D8%B9%D9%8A-%D9%88%D8%A2%D9%84%D9%8A%D8%A9-%D8%B9%D9%85%D9%84%D9%87%D8%A7-r526/" rel="">مواقع التواصل الاجتماعي</a> التي تزورها عادة.
	</li>
</ul>

<h2 id="requests">
	تنزيل الملفات من الويب باستخدام الوحدة requests
</h2>

<p>
	تسمح لك الوحدة <code>requests</code> بتنزيل الملفات من الويب دون أن تفكر في مشاكل <a href="https://academy.hsoub.com/devops/networking/%D8%B4%D8%A8%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D8%A8/" rel="">الشبكة</a> أو الاتصال أو ضغط البيانات. لا تأتي الوحدة <code>requests</code> مضمنةً في بايثون، وإنما عليك تثبيتها أولًا من سطر الأوامر بتشغيل الأمر <code>pip install --user requests</code>.
</p>

<p>
	أتت الوحدة <code>requests</code> لتقدم حلًا بديلًا لوحدة <code>urllib2</code> في بايثون لأنها معقدة زيادة عن اللزوم، وأنصحك أن تزيل الوحدة <code>urllib2</code> من ذهنك تمامًا، لأنها وحدة صعبة دون داعٍ، وعليك استخدام الوحدة <code>requests</code> دومًا.
</p>

<p>
	لنجرب الآن أن الحزمة <code>requests</code> مثبتة صحيحًا بإدخال ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9154_37" style=""><span class="kwd">import</span><span class="pln"> requests</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> requests</span></pre>

<p>
	إذا لم تظهر أي رسالة خطأ فهذا يعني أن الحزمة <code>requests</code> مثبتة عندك.
</p>

<h3 id="requestsget">
	تنزيل صفحة ويب باستخدام الدالة requests.get()‎
</h3>

<p>
	الدالة <code>requests.get()‎</code> تقبل سلسلةً نصيةً فيها رابط URL لتنزيلها. إذا استعملت الدالة <code>type()‎</code> على القيمة المعادة من الدالة <code>requests.get()‎</code> فسترى أن الناتج هو كائن <code>Response</code>، الذي يحتوي على الرد الذي تلقاه برنامجك بعد إتمام الطلبية إلى <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r574/" rel="">خادم الويب</a>. سنستكشف سويةً الكائن <code>Response</code> بالتفصيل لاحقًا، لكن لنكتب الآن الأسطر الآتية في الطرفية التفاعلية على حاسوب متصل بالإنترنت:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9154_39" style=""><span class="pln">   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> requests
</span><span class="pun">➊</span><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> res </span><span class="pun">=</span><span class="pln"> requests</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'https://automatetheboringstuff.com/files/rj.txt'</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> type</span><span class="pun">(</span><span class="pln">res</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">&lt;</span><span class="kwd">class</span><span class="pln"> </span><span class="str">'requests.models.Response'</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">➋</span><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> res</span><span class="pun">.</span><span class="pln">status_code </span><span class="pun">==</span><span class="pln"> requests</span><span class="pun">.</span><span class="pln">codes</span><span class="pun">.</span><span class="pln">ok
   </span><span class="kwd">True</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">res</span><span class="pun">.</span><span class="pln">text</span><span class="pun">)</span><span class="pln">
   </span><span class="lit">178981</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">res</span><span class="pun">.</span><span class="pln">text</span><span class="pun">[:</span><span class="lit">250</span><span class="pun">])</span><span class="pln">
   </span><span class="typ">The</span><span class="pln"> </span><span class="typ">Project</span><span class="pln"> </span><span class="typ">Gutenberg</span><span class="pln"> </span><span class="typ">EBook</span><span class="pln"> of </span><span class="typ">Romeo</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="typ">Juliet</span><span class="pun">,</span><span class="pln"> by </span><span class="typ">William</span><span class="pln"> </span><span class="typ">Shakespeare</span><span class="pln">

   </span><span class="typ">This</span><span class="pln"> eBook </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> the use of anyone anywhere at no cost </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">with</span><span class="pln">
   almost no restrictions whatsoever</span><span class="pun">.</span><span class="pln">  </span><span class="typ">You</span><span class="pln"> may copy it</span><span class="pun">,</span><span class="pln"> give it away </span><span class="kwd">or</span><span class="pln">
   re</span><span class="pun">-</span><span class="pln">use it under the terms of the </span><span class="typ">Proje</span></pre>

<p>
	الرابط الذي طلبناه هو مستند نصي لمسرحية روميو وجولييت على موقع الكتاب الأصلي ➊، يمكنك أن ترى نجاح الطلبية إلى صفحة الويب بالنظر إلى السمة <code>status_code</code> من الكائن <code>Response</code>، إذا كانت القيمة الخاصة بها تساوي <code>requests.codes.ok</code> فهذا يعني أن كل شيء على ما يرام ➋.
</p>

<p>
	بالمناسبة، رمز الاستجابة الذي يدل على أن الأمور على ما يرام OK في HTTP هو 200، ومن المرجح أنك تعرف الحالة 404 التي تشير إلى رابط غير موجود. يمكنك العثور على قائمة برموز الاستجابة في HTTP ومعانيها في الصفحة <a href="https://en.wikipedia.org/wiki/ListofHTTP_status_codes" rel="external nofollow">قائمة رموز الاستجابة في HTTP من ويكيبيديا</a>.
</p>

<p>
	إذا نجحت الطلبية، فستخزن صفحة الويب التي نزلناها كسلسلة نصية في المتغير <code>text</code> في كائن <code>Response</code>. يحتوي هذا المتغير على سلسلة نصية طويلة فيها المسرحية كاملةً. وإذا استدعيت <code>len(res.text)‎</code> فسترى أنها أطول من 178,000 محرف. استدعينا في النهاية <code>print(res.text[:250])‎</code> لعرض أول 250 محرف.
</p>

<p>
	إذا فشل الطلب وظهرت رسالة خطأ مثل "Failed to establish a new connection" أو "Max retries exceeded" فتأكد من اتصالك بالإنترنت. لا نستطيع نقاش جميع أسباب عدم القدرة على الاتصال بالخوادم لتعقيد الموضوع، لكن أنصحك بالبحث في الويب عن المشكلة التي تواجهك لترى حلها.
</p>

<h3 id="-1">
	التأكد من عدم وجود مشاكل
</h3>

<p>
	كما رأينا سويةً، يملك الكائن <code>Response</code> السمة <code>status_code</code> التي تأكدنا أنها تساوي <code>requests.codes.ok</code> (وهو متغير فيه القيمة الرقمية 200) للتحقق من نجاح عملية التنزيل.
</p>

<p>
	هنالك طريقة أخرى سهلة للتحقق من نجاح التنفيذ هو استدعاء التابع <code>raise_for_status()‎</code> على الكائن <code>Response</code>، التي ستؤدي إلى إطلاق استثناء إذا حدث خطأ حين تنزيل الملف، ولن تفعل شيئًا إن سارت الأمور على ما يرام. جرب ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9154_41" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> res </span><span class="pun">=</span><span class="pln"> requests</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'https://inventwithpython.com/page_that_does_not_exist'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> res</span><span class="pun">.</span><span class="pln">raise_for_status</span><span class="pun">()</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;stdin&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">

  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"C:\Users\Al\AppData\Local\Programs\Python\Python37\lib\site-packages\requests\models
.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">940</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> raise_for_status
    </span><span class="kwd">raise</span><span class="pln"> </span><span class="typ">HTTPError</span><span class="pun">(</span><span class="pln">http_error_msg</span><span class="pun">,</span><span class="pln"> response</span><span class="pun">=</span><span class="pln">self</span><span class="pun">)</span><span class="pln">
requests</span><span class="pun">.</span><span class="pln">exceptions</span><span class="pun">.</span><span class="typ">HTTPError</span><span class="pun">:</span><span class="pln"> </span><span class="lit">404</span><span class="pln"> </span><span class="typ">Client</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Not</span><span class="pln"> </span><span class="typ">Found</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> url</span><span class="pun">:</span><span class="pln"> https</span><span class="pun">://</span><span class="pln">inventwithpython
</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">page_that_does_not_exist</span><span class="pun">.</span><span class="pln">html</span></pre>

<p>
	يضمن لنا التابع <code>()raise_for_status</code> أن البرنامج سيتوقف إذا حدثت مشكلة في التنزيل، وهذا مناسب جدًا إذا أردنا إيقاف البرنامج حين حصول مشكلة في التنزيل. أما لو كنا نريد استمرار البرنامج حتى لو فشل تنزيل الملف فيمكننا حينئذٍ أن نحيط التابع <code>raise_for_status()‎</code> بالتعبيرات <code>try</code> و <code>except</code> لمعالجة هذا الاستثناء:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9154_43" style=""><span class="kwd">import</span><span class="pln"> requests
res </span><span class="pun">=</span><span class="pln"> requests</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'https://inventwithpython.com/page_that_does_not_exist'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">raise_for_status</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">except</span><span class="pln"> </span><span class="typ">Exception</span><span class="pln"> </span><span class="kwd">as</span><span class="pln"> exc</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'There was a problem: %s'</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">exc</span><span class="pun">))</span></pre>

<p>
	التابع <code>raise_for_status()</code><code>‎</code> في الشيفرة السابقة سيؤدي إلى طباعة ما يلي:
</p>

<pre class="ipsCode" id="ips_uid_9154_48">There was a problem: 404 Client Error: Not Found for url: https://
inventwithpython.com/page_that_does_not_exist.html</pre>

<p>
	احرص دومًا على استدعاء التابع <code>raise_for_status() </code>بعد استدعاء <code>requests.get()‎</code> لتضمن أن برنامجك قد نزَّل الملف دون مشاكل قبل إكمال التنفيذ.
</p>

<h3 id="-2">
	حفظ الملفات المنزلة إلى نظام الملفات
</h3>

<p>
	يمكنك الآن حفظ صفحة الويب إلى نظام الملفات لديك باستخدام الدالة <code>open()‎</code> والتابع <code>write()‎</code>، هنالك بعض الاختلافات البسيطة عمّا فعلناه سابقًا: علينا أن نفتح الملف في وضع الكتابة <a href="https://academy.hsoub.com/programming/os-embedded-systems/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D8%B9%D8%AF-%D8%A7%D9%84%D8%AB%D9%86%D8%A7%D8%A6%D9%8A-binary-%D8%A3%D8%B3%D8%A7%D8%B3-%D8%A7%D9%84%D8%AD%D9%88%D8%B3%D8%A8%D8%A9-r1658/" rel="">بالنظام الثنائي write binary</a> بتمرير السلسلة النصية <code>'wb'</code> كوسيط ثانٍ إلى الدالة <code>open()‎</code> حتى لو كان الملف المنزل نصيًا (مثل مسرحية روميو وجولييت في المثال أعلاه)، لأننا نريد كتابة البيانات الثنائية بدلًا من البيانات النصية للحفاظ على ترميز النص encoding.
</p>

<p>
	لنستعمل <a href="https://wiki.hsoub.com/Python/for" rel="external">حلقة for</a> مع التابع <code>iter_content()‎</code> للكائن <code>Response</code> لكتابة صفحة الويب إلى ملف:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9154_51" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> requests
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> res </span><span class="pun">=</span><span class="pln"> requests</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'https://automatetheboringstuff.com/files/rj.txt'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> res</span><span class="pun">.</span><span class="pln">raise_for_status</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> playFile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'RomeoAndJuliet.txt'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'wb'</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"> chunk </span><span class="kwd">in</span><span class="pln"> res</span><span class="pun">.</span><span class="pln">iter_content</span><span class="pun">(</span><span class="lit">100000</span><span class="pun">):</span><span class="pln">
        playFile</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">chunk</span><span class="pun">)</span><span class="pln">

</span><span class="lit">100000</span><span class="pln">
</span><span class="lit">78981</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> playFile</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	يعيد التابع <code>iter_content()‎</code> قطعًا من النص في كل تكرار لحلقة التكرار، وكل قطعة يكون لها نوع البيانات bytes وتحدد لها كم بايتًا يجب أن يكون طول كل قطعة، وأرى أن مئة ألف بايت هو حجم مناسب، لذا لنمرر 100000 إلى التابع <code>iter_content()‎</code>.
</p>

<p>
	أنشأنا الآن الملف <code>RomeoAndJuliet.txt</code> في مجلد العمل الحالي، لاحظ أن اسم الملف في موقع الويب هو rj.txt بينما اسم الملف المحفوظ لدينا مختلف. تذكر أن الوحدة <code>requests</code> تنزل محتويات صفحات الويب لديك، وبعد تنزيلها يكون على عاتقك التعامل معها وحفظها إن شئت أينما تشاء.
</p>

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

	<div class="ipsQuote_contents ipsClearfix" data-gramm="false">
		<p>
			ترميز يونيكود Unicode encoding: ترميز يونيكود خارج عن نطاق هذه السلسلة، لكن يمكنك قراءة المزيد عنه في مقال <a href="https://www.joelonsoftware.com/articles/Unicode.html" rel="external nofollow">The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets</a> ومقال <a href="https://nedbatchelder.com/text/unipain.html" rel="external nofollow">Pragmatic Unicode</a>.
		</p>

		<p>
			يعيد التابع  <code>()write</code> عدد البايتات المكتوبة إلى ملف، وكتبنا في المثال السابق 100,000 بايت إلى الملف في أول «قطعة» chunk وبقي له 78,981 بايت للكتابة للمرة الثانية.
		</p>
	</div>
</blockquote>

<p>
	للمراجعة، هذه هي الخطوات الكاملة لتنزيل وحفظ ملف:
</p>

<ol>
	<li>
		استدعاء التابع <code>requests.get()‎</code> لتنزيل ملف.
	</li>
	<li>
		استدعاء <code>open()‎</code> مع الخيار <code>'wb'</code> لإنشاء ملف جديد وفتحه للكتابة في الوضع الثنائي.
	</li>
	<li>
		المرور على التابع <code>iter_content()‎</code> للكائن <code>Response</code>.
	</li>
	<li>
		استدعاء التابع <code>write()‎</code> في كل تكرار لكتابة المحتوى إلى الملف.
	</li>
	<li>
		إغلاق الملف <code>close()‎</code>.
	</li>
</ol>

<p>
	هذا كل ما يتعلق بالوحدة <code>requests!</code> قد تبدو لك حلقة <code>for</code> مع <code>iter_content()‎</code> معقدةً مقارنةً باستخدام <code>open()‎</code> و <code>write()‎</code> و <code>close()‎</code> التي استخدمناها لكتابة الملفات النصية؛ لكننا فعلنا ذلك لنضمن أن برنامجنا لن يستهلك ذاكرة كثيرة إذا نزلنا ملفات ضخمة. يمكنك قراءة المزيد حول ميزات الوحدة <code>requests</code> الأخرى من <a href="https://requests.readthedocs.org/" rel="external nofollow">requests.readthedocs.org</a>.
</p>

<h2 id="html">
	لغة HTML
</h2>

<p>
	قبل أن نستخلص المعلومات من صفحات الويب، لنتعلم بعض <a href="https://academy.hsoub.com/programming/html/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-html-r1687/" rel="">أساسيات HTML</a> أولًا، ولنرى كيف نصل إلى أدوات المطور في متصفح الويب، التي ستجعل عملية استخراج البيانات من الويب أمرًا سهلًا جدًا.
</p>

<h3 id="html-1">
	مصادر لتعلم HTML
</h3>

<p>
	<a href="https://academy.hsoub.com/programming/html/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-html-r1702/" rel="">لغة HTML</a> هي الصيغة التي تكتب فيها صفحات الويب، ويفترض هذا المقال أن لديك بعض الأساسيات حول HTML، لكن إن كنت تريد البدء من الصفر فأنصحك أن تراجع:
</p>

<ul>
	<li>
		<a href="https://wiki.hsoub.com/HTML" rel="external">توثيق HTML</a> في موسوعة حسوب.
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/html/" rel="">قسم HTML</a> في أكاديمية حسوب.
	</li>
</ul>

<h3 id="-3">
	تذكرة سريعة
</h3>

<p>
	في حال لم تلمس HTML من مدة، سأخبرك بملخص بسيط عنها.
</p>

<p>
	ملفات HTML هي ملفات نصية لها اللاحقة html، وتكون النصوص فيها محادثة بالوسوم tags، وكل وسم يكون ضمن قوسي زاوية &lt;&gt;، وتخبر هذه الوسوم المتصفحات كيف يجب أن تعرض الصفحة.
</p>

<p>
	يمكن أن يكون هنالك نص بين وسم البداية ووسم النهاية، وهذا ما يؤلف عنصرًا element. فمثلًا، الشيفرة الآتية تعرض لك Hello, world!‎ في المتصفح، وتكون كلمة Hello بخط عريض:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7031_14" style=""><span class="tag">&lt;strong&gt;</span><span class="pln">Hello</span><span class="tag">&lt;/strong&gt;</span><span class="pln">, world!</span></pre>

<p>
	وستبدو في المتصفح كما في الشكل الآتي:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="153632" data-ratio="32.74" data-unique="hlkxeco48" width="565" alt="Hello, world!.jpg" src="https://academy.hsoub.com/uploads/monthly_2024_07/Helloworld!.jpg.af29dc6b2be6ff195b25e91a445ead6c.jpg">
</p>

<p style="text-align: center;">
	مثال Hello, world!‎ معروضة في متصفح
</p>

<p>
	وسم البداية <code><a href="https://wiki.hsoub.com/HTML/strong" rel="external">&lt;strong&gt;</a></code> يخبر المتصفح أن النص سيكون بخط عريض، ووسم النهاية <code>&lt;‎/strong&gt;</code> يخبر المتصفح أين هي نهاية النص العريض. هنالك وسوم متنوعة في HTML، ولبعض تلك الوسوم خاصيات تُذكَر ضمن قوسَي الزاوية <code>&lt;&gt;</code>، مثلًا <a href="https://wiki.hsoub.com/HTML/a" rel="external">الوسم &lt;a&gt;</a> يعني أن النص هو رابط، وتكون قيمة هذا الرابط محددة <a href="https://wiki.hsoub.com/HTML/a#href" rel="external">بالخاصية href</a><code></code>. مثال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7031_16" style=""><span class="pln">Al's free </span><span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"https://inventwithpython.com"</span><span class="tag">&gt;</span><span class="pln">Python books</span><span class="tag">&lt;/a&gt;</span><span class="pln">.</span></pre>

<p>
	ستبدو صفحة الويب كما في الشكل الآتي:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="153633" data-ratio="32.74" data-unique="tq69qe17r" width="565" alt="رابط معروض في متصفح.jpg" src="https://academy.hsoub.com/uploads/monthly_2024_07/438404959_.jpg.70616a072b043e7dd23cd510a7d5a765.jpg">
</p>

<p style="text-align: center;">
	رابط معروض في متصفح.
</p>

<p>
	تمتلك بعض العناصر <a href="https://wiki.hsoub.com/HTML/Global_Attributes#id" rel="external">الخاصية id</a> التي تستخدم لتعريف عناصر الصفحة بشكل فريد، ويمكنك أن تطلب من برامجك البحث عن عنصر ما باستخدام معرفه id، لهذا تكون معرفة قيمة id لأحد العناصر من أهم الأمور التي سنستعمل فيها أدوات المطور أثناء كتابة برامج استخلاص البيانات من صفحات الويب.
</p>

<h3 id="html-2">
	عرض مصدر صفحة HTML
</h3>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2024_07/1977032677_.jpg.cda245870170152f4d7aa8f2fb723dd7.jpg" data-fileid="153634" data-fileext="jpg" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="153634" data-ratio="97.24" data-unique="pqi9g6m50" width="617" alt="عرض مصدر صفحة ويب.jpg" src="https://academy.hsoub.com/uploads/monthly_2024_07/.thumb.jpg.89794b00b2feb10bd8ab34c43d9c3a38.jpg"></a>
</p>

<p style="text-align: center;">
	عرض مصدر صفحة ويب
</p>

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

<h3 id="-4">
	فتح أدوات المطور
</h3>

<p>
	إضافةً إلى عرض المصدر، يمكنك أن تلقي نظرة على صفحات HTML باستخدام أدوات المطور في متصفحك. يمكنك أن تضغط الزر F12 في كروم لإظهارها، أو الضغط على F12 مرة أخرى لإخفائها. يمكنك أيضًا فتحها من القائمة الجانبية ثم Developer Tools، أو الضغط على <code>‏‎⌘-⌥-I</code> في ماك.
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="153635" data-ratio="54.61" data-unique="9b5id0d8t" width="694" alt="أدوات المطور في متصفح كروم.jpg" src="https://academy.hsoub.com/uploads/monthly_2024_07/987726624_.jpg.a7c6c07a7486342ec7b40da5e53a295f.jpg">
</p>

<p style="text-align: center;">
	أدوات المطور في متصفح كروم
</p>

<p>
	أما في فايرفكس، فيمكنك فتح <a href="https://academy.hsoub.com/programming/workflow/%D8%A3%D8%AF%D9%88%D8%A7%D8%AA-%D9%85%D8%B7%D9%88%D8%B1%D9%8A-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D9%85%D8%AF%D9%85%D8%AC%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-r1439/" rel="">أدوات المطور</a> بالضغط على <code>Ctrl+Shift+C</code> في ويندوز ولينكس، أو <code>‏‎⌘-⌥-C</code> في ماك، وأدوات المطور هنا تشبه كروم كثيرًا.
</p>

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

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

	<p data-gramm="false">
		لا تستعمل التعابير النمطية لتفسير HTML: قد تظن أن التعابير النمطية هي الأداة الأمثل العثور على سلسلة نصية معينة في HTML، لكنني أنصحك بعدم فعل ذلك، لأن هنالك طرائق كثيرة يمكننا كتابة شيفرات HTML سليمة، ومحاولة تغطية جميع حالات الاستخدام يدويًا باستخدام التعابير النمطية هو أمر مرهق ومعرض للخطأ كثيرًا. هنالك وحدات مطورة خصيصًا لتفسير شيفرات HTML مثل <code>bs4</code>، التي ستقلل كثيرًا من العلل والأخطاء وتسهل عليك العمل.
	</p>
</blockquote>

<h3 id="html-3">
	استخدام أدوات المطور للعثور على عناصر HTML
</h3>

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

<p>
	ستساعدنا هنا أدوات المطور في ذلك. لنقل مثلًا أننا نريد كتابة برنامج لجلب بيانات الطقس من موقع <a href="https://www.weather.gov/" rel="external nofollow">weather.gov</a>. لكن قبل أن نبدأ بكتابة الشيفرات فعلينا القيام ببعض التحريات أولًا. إذا زرنا الموقع وبحثنا عن الرمز البريدي 94105 فستحصل على صفحة تظهر لك الطقس في تلك المنطقة.
</p>

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

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="153636" data-ratio="77.95" data-unique="atl4zvnjf" width="694" alt="تفحص عناصر صفحة الطقس باستخدام أدوات المطور.jpg" src="https://academy.hsoub.com/uploads/monthly_2024_07/554571706_.jpg.64e028a988d8b4fc8f681df2145dba96.jpg">
</p>

<p style="text-align: center;">
	تفحص عناصر صفحة الطقس باستخدام أدوات المطور
</p>

<p>
	يمكننا أن نرى ما هي شيفرة HTML المسؤولة عن عرض الطقس في الصفحة السابقة، وهي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7031_64" style=""><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-sm-10 forecast-text"</span><span class="tag">&gt;</span><span class="pln">Sunny, with a high near 64. West wind 11 to 16 mph, with gusts as high as 21 mph.</span><span class="tag">&lt;/div&gt;</span><span class="pln"> </span></pre>

<p>
	هذا ما نبحث عنه تمامًا، يبدو أن معلومات الطقس موجودة داخل <a href="https://wiki.hsoub.com/HTML/div" rel="external">عنصر &lt;div&gt;</a> له صنف <a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> باسم <code>forecast-text</code>. اضغط بالزر الأيمن على العنصر في أدوات المطور واختر من القائمة Copy ▸ CSS Selector، وستُنسَخ لك سلسلة نصية مثل الآتية إلى الحافظة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_357_7" style=""><span class="str">'div.row-odd:nth-child(1) &gt; div:nth-child(2)'</span><span class="pln"> </span></pre>

<p>
	ويمكنك أن تستخدم تلك السلسلة النصية مع التابع <code>ذ</code> في <code>BS4</code> أو <code>find_element_by_css_selector()‎</code> في <code>Selenium</code> كما هو مشروح في هذا المقال.
</p>

<p>
	الآن وبعد أن عرفت ما الذي تبحث عنه تحديدًا، يمكن لوحدة <code>Beautiful Soup</code> أن تساعدك في العثور عليه.
</p>

<h2 id="htmlbs4">
	تفسير HTML مع وحدة BS4
</h2>

<p>
	تستخدم الوحدة <code>Beautiful Soup</code> في استخراج المعلومات من صفحة HTML، واسم الوحدة في بايثون هو <code>bs4</code> للإشارة إلى الإصدار الرابع منها، ويمكننا تثبيتها عبر الأمر <code>pip install --user beautifulsoup4</code> (راجع الملحق أ لتعليمات حول تثبيت الوحدات). صحيح أننا استخدمنا <code>beautifulsoup4</code> لتثبيت الوحدة، لكن حين استيرادها في بايثون سنستعمل <code>import bs4</code>.
</p>

<p>
	ستكون أمثلتنا عن <code>BS4</code> عن تفسير ملف HTML (أي تحليلها والتعرف على أجزائها) مخزن محليًا على حاسوبنا. افتح لسانًا جديدًا في محرر Mu وأدخل ما يلي فيه واحفظه باسم <code>example.html</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7031_19" style=""><span class="com">&lt;!-- This is the example.html example file. --&gt;</span><span class="pln">

</span><span class="tag">&lt;html&gt;&lt;head&gt;&lt;title&gt;</span><span class="pln">The Website Title</span><span class="tag">&lt;/title&gt;&lt;/head&gt;</span><span class="pln">
</span><span class="tag">&lt;body&gt;</span><span class="pln">
</span><span class="tag">&lt;p&gt;</span><span class="pln">Download my </span><span class="tag">&lt;strong&gt;</span><span class="pln">Python</span><span class="tag">&lt;/strong&gt;</span><span class="pln"> book from </span><span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"https://
inventwithpython.com"</span><span class="tag">&gt;</span><span class="pln">my website</span><span class="tag">&lt;/a&gt;</span><span class="pln">.</span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"slogan"</span><span class="tag">&gt;</span><span class="pln">Learn Python the easy way!</span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;p&gt;</span><span class="pln">By </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"author"</span><span class="tag">&gt;</span><span class="pln">Al Sweigart</span><span class="tag">&lt;/span&gt;&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;&lt;/html&gt;</span></pre>

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

<h3 id="beautifulsouphtml">
	إنشاء كائن BeautifulSoup من سلسلة HTML نصية
</h3>

<p>
	يمكننا استدعاء الدالة <code>bs4.BeautifulSoup()‎</code> مع تمرير سلسلة نصية تحتوي على شيفرة HTML التي ستفسر. تعيد الدالة <code>bs4.BeautifulSoup()</code><code>‎</code> كائن <code>BeautifulSoup</code>. جرب ما يلي في الصدفة التفاعلية على حاسوبك مع وجود إنترنت:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7031_21" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> requests</span><span class="pun">,</span><span class="pln"> bs4
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> res </span><span class="pun">=</span><span class="pln"> requests</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'https://academy.hsoub.com'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> res</span><span class="pun">.</span><span class="pln">raise_for_status</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> academySoup </span><span class="pun">=</span><span class="pln"> bs4</span><span class="pun">.</span><span class="typ">BeautifulSoup</span><span class="pun">(</span><span class="pln">res</span><span class="pun">.</span><span class="pln">text</span><span class="pun">,</span><span class="pln"> </span><span class="str">'html.parser'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> type</span><span class="pun">(</span><span class="pln">academySoup</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="kwd">class</span><span class="pln"> </span><span class="str">'bs4.BeautifulSoup'</span><span class="pun">&gt;</span></pre>

<p>
	هذه الشيفرة تستعمل <code>requests.get()‎</code> لتنزيل صفحة الويب من موقع أكاديمية حسوب ثم تمرر قيمة السمة <code>text</code> للرد إلى الدالة <code>bs4.BeautifulSoup()‎</code> التي تعيد كائن <code>BeautifulSoup</code> نخزنه في المتغير <code>academySoup</code>.
</p>

<p>
	يمكننا أيضًا تحميل ملف HTML من القرص لدينا بتمرير كائن <code>File</code> إلى الدالة <code>bs4.BeautifulSoup()‎</code> مع وسيط ثانٍ يخبر وحدة <code>BS4</code> ما المفسر الذي عليها استعماله لتفسير الملف.
</p>

<p>
	أدخل ما يلي في الصدفة التفاعلية مع التأكد أنك في نفس المجلد الذي يحتوي على ملف <code>example.html</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7031_23" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> exampleFile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'example.html'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> exampleSoup </span><span class="pun">=</span><span class="pln"> bs4</span><span class="pun">.</span><span class="typ">BeautifulSoup</span><span class="pun">(</span><span class="pln">exampleFile</span><span class="pun">,</span><span class="pln"> </span><span class="str">'html.parser'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> type</span><span class="pun">(</span><span class="pln">exampleSoup</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="kwd">class</span><span class="pln"> </span><span class="str">'bs4.BeautifulSoup'</span><span class="pun">&gt;</span></pre>

<p>
	المفسر <code>'html.parser'</code> المستخدم هنا يأتي مع بايثون، لكن يمكنك استخدام المفسر <code>'lxml'</code> الأسرع إذا ثبتت الوحدة الخارجية <code>lxml.</code> اتبع التعليمات الموجودة في الملحق أ لتثبيت الوحدة باستخدام الأمر <code>pip install --user lxml</code>. إذا لم نضمِّن الوسيط الثاني الذي يحدد المفسر فسيظهر التحذير: UserWarning: No parser was explicitly specified.
</p>

<p>
	بعد أن يكون لدينا كائن <code>BeautifulSoup</code> سنتمكن من استخدام توابعه لتحديد أجزاء معينة من مستند HTML.
</p>

<h3 id="select">
	العثور على عنصر باستخدام التابع select()‎
</h3>

<p>
	يمكنك الحصول على عنصر من عناصر صفحة الويب في الكائن <code>BeatuifulSoup</code> باستدعاء التابع <code>select()‎</code> وتمرير <a href="https://academy.hsoub.com/programming/css/%D8%A7%D9%84%D9%85%D8%AD%D8%AF%D8%AF%D8%A7%D8%AA-selectors-%D9%81%D9%8A-css-r249/" rel="">محدد CSS</a> (أي CSS Selector) للعنصر الذي تبحث عنه. المحددات تشبه التعابير النمطية في وظيفتها: تحدد نمطًا يمكن البحث عنه في صفحات الويب.
</p>

<p>
	نقاش محددات CSS خارج سياق هذه السلسلة، لكن هذه مقدمة مختصرة عنها في الجدول التالي، وأنصحك بالاطلاع على <a href="https://wiki.hsoub.com/CSS#.D8.A7.D9.84.D9.85.D9.8F.D8.AD.D8.AF.D9.90.D9.91.D8.AF.D8.A7.D8.AA_.D9.81.D9.8A_.D9.84.D8.BA.D8.A9_CSS" rel="external">توثيق المحددات في موسوعة حسوب</a>.
</p>

<table>
	<thead>
		<tr>
			<th>
				المحدد الذي يمرر إلى التابع ()select
			</th>
			<th>
				سيطابق
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				soup.select('div')
			</td>
			<td>
				جميع عناصر <code>&lt;div&gt;</code>
			</td>
		</tr>
		<tr>
			<td>
				soup.select('#author')
			</td>
			<td>
				جميع العناصر التي لها الخاصية <code>id</code> وقيمتها <code>author</code>
			</td>
		</tr>
		<tr>
			<td>
				soup.select('.notice')
			</td>
			<td>
				جميع العناصر التي لها خاصية <code>class</code> ولها صنف CSS باسم <code>notice</code>
			</td>
		</tr>
		<tr>
			<td>
				soup.select('div span')
			</td>
			<td>
				جميع <a href="https://wiki.hsoub.com/HTML/span" rel="external">عناصر &lt;span&gt;</a> الموجود داخل عناصر <code>&lt;div&gt;</code>
			</td>
		</tr>
		<tr>
			<td>
				soup.select('div &gt; span')
			</td>
			<td>
				جميع العناصر <code>&lt;span&gt;</code> الموجودة مباشرةً داخل عناصر <code>&lt;div&gt;</code> بدون وجود أي عنصر بينهما
			</td>
		</tr>
		<tr>
			<td>
				soup.select('input[name]')
			</td>
			<td>
				جميع <a href="https://wiki.hsoub.com/HTML/input" rel="external">عناصر &lt;input&gt;</a> التي لها الخاصية <code>name</code> بغض النظر عن قيمتها
			</td>
		</tr>
		<tr>
			<td>
				soup.select('input[type="button"]')
			</td>
			<td>
				جميع عناصر <code>&lt;input&gt;</code> التي لها الخاصية <code>type</code> وتكون مساوية إلى <code>button</code>
			</td>
		</tr>
	</tbody>
</table>

<p style="text-align: center;">
	أمثلة عن محددات CSS
</p>

<p>
	يمكن دمج مختلف أنماط المحددات مع بعضها لمطابقة أنماط أكثر تعقيدًا، فمثلًا <code>soup.select('p #author')‎</code> ستطابق أي عنصر له خاصية <code>id</code> قيمتها <code>author</code> لكن يجب أن يكون هذا العنصر موجودًا داخل <a href="https://wiki.hsoub.com/HTML/p" rel="external">عنصر &lt;p&gt;</a>.
</p>

<p>
	بدلًا من محاولة كتابة المحددات بنفسك، يمكنك الضغط بالزر الأيمن على أي عنصر في صفحة الويب واختيار Inspect Element، وحينما تفتح أدوات المطور اضغط بالزر الأيمن على عنصر HTML واختر Copy ▸ CSS Selector لنسخ محدد CSS إلى الحافظة لتستطيع لصقه في الشيفرة لديك.
</p>

<p>
	التابع <code>select()‎</code> سيعيد قائمةً بعناصر <code>Tag</code>، وهذا ما تفعله وحدة <code>BS4</code> لتمثيل عنصر HTML. هذه القائمة ستحتوي على كائن <code>Tag</code> لكل مطابقة للمحدد في كائن <code>BeautifulSoup</code>. يمكن تمرير كائن <code>Tag</code> إلى الدالة <code>str()‎</code> لعرض وسوم HTML التي تمثلها.
</p>

<p>
	تمتلك قيم <code>Tag</code> أيضًا السمة <code>attrs</code> التي تظهر جميع خاصيات HTML للعنصر ممثلةً كقاموس. لنجرب على ملف <code>example.html</code> بإدخال ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7031_25" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> bs4
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> exampleFile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'example.html'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> exampleSoup </span><span class="pun">=</span><span class="pln"> bs4</span><span class="pun">.</span><span class="typ">BeautifulSoup</span><span class="pun">(</span><span class="pln">exampleFile</span><span class="pun">.</span><span class="pln">read</span><span class="pun">(),</span><span class="pln"> </span><span class="str">'html.parser'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> elems </span><span class="pun">=</span><span class="pln"> exampleSoup</span><span class="pun">.</span><span class="pln">select</span><span class="pun">(</span><span class="str">'#author'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> type</span><span class="pun">(</span><span class="pln">elems</span><span class="pun">)</span><span class="pln"> </span><span class="com"># elems هي قائمة من كائنات Tag</span><span class="pln">
</span><span class="pun">&lt;</span><span class="kwd">class</span><span class="pln"> </span><span class="str">'list'</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">elems</span><span class="pun">)</span><span class="pln">
</span><span class="lit">1</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> type</span><span class="pun">(</span><span class="pln">elems</span><span class="pun">[</span><span class="lit">0</span><span class="pun">])</span><span class="pln">
</span><span class="pun">&lt;</span><span class="kwd">class</span><span class="pln"> </span><span class="str">'bs4.element.Tag'</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">elems</span><span class="pun">[</span><span class="lit">0</span><span class="pun">])</span><span class="pln"> </span><span class="com"># تحويل الكائن إلى سلسلة نصية.</span><span class="pln">
</span><span class="str">'&lt;span id="author"&gt;Al Sweigart&lt;/span&gt;'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> elems</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">getText</span><span class="pun">()</span><span class="pln">
</span><span class="str">'Al Sweigart'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> elems</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">attrs
</span><span class="pun">{</span><span class="str">'id'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'author'</span><span class="pun">}</span></pre>

<p>
	ستستخرج الشيفرة السابقة العنصر الذي له <code>id="author"‎</code> في مستند HTML. سنستخدم <code>select('#author')‎</code> للحصول على قائمة بجميع العناصر التي لها <code>id="author"‎</code>، وسنخزن قائمة كائنات <code>Tag</code> في المتغير <code>elems</code>، وسيخبرنا التعبير <code>len(elems)‎</code> أن لدينا كائن <code>Tag</code> وحيد في القائمة، أي جرت عملية المطابقة لعنصر HTML وحيد.
</p>

<p>
	استدعاء التابع <code>getText()‎</code> على العناصر سيعيد النص الموجود في العنصر، أي السلسلة النصية الموجودة بين وسم البدء والإغلاق.
</p>

<p>
	أما تمرير الكائن إلى الدالة <code>str()‎</code> سيعيد سلسلة نصيةً فيها وسمَي البداية والنهاية مع نص العنصر؛ أما السمة <code>attrs</code> فستعطينا قاموسًا فيه خاصيات العنصر كاملةً.
</p>

<p>
	يمكنك أيضًا استخراج جميع عناصر <code>&lt;p&gt;</code> من كائن <code>BeautifulSoup</code> كما في المثال الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7031_27" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> pElems </span><span class="pun">=</span><span class="pln"> exampleSoup</span><span class="pun">.</span><span class="pln">select</span><span class="pun">(</span><span class="str">'p'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">pElems</span><span class="pun">[</span><span class="lit">0</span><span class="pun">])</span><span class="pln">
</span><span class="str">'&lt;p&gt;Download my &lt;strong&gt;Python&lt;/strong&gt; book from &lt;a href="https://
inventwithpython.com"&gt;my website&lt;/a&gt;.&lt;/p&gt;'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> pElems</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">getText</span><span class="pun">()</span><span class="pln">
</span><span class="str">'Download my Python book from my website.'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">pElems</span><span class="pun">[</span><span class="lit">1</span><span class="pun">])</span><span class="pln">
</span><span class="str">'&lt;p class="slogan"&gt;Learn Python the easy way!&lt;/p&gt;'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> pElems</span><span class="pun">[</span><span class="lit">1</span><span class="pun">].</span><span class="pln">getText</span><span class="pun">()</span><span class="pln">
</span><span class="str">'Learn Python the easy way!'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">pElems</span><span class="pun">[</span><span class="lit">2</span><span class="pun">])</span><span class="pln">
</span><span class="str">'&lt;p&gt;By &lt;span id="author"&gt;Al Sweigart&lt;/span&gt;&lt;/p&gt;'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> pElems</span><span class="pun">[</span><span class="lit">2</span><span class="pun">].</span><span class="pln">getText</span><span class="pun">()</span><span class="pln">
</span><span class="str">'By Al Sweigart'</span></pre>

<p>
	ستعطينا <code>select()‎</code> ثلاث مطابقات، والتي ستخزن في المتغير <code>pElems</code>. سنجرب استخدام <code>str()‎</code> على الكائنات <code>pElems[0]‎</code> و <code>pElems[1]‎</code> و <code>pElems[2]‎</code> لعرض العناصر كسلاسل نصية، وسنجرب أيضًا التابع <code>getText()‎</code> لإظهار نص تلك العناصر فقط.
</p>

<h3 id="-5">
	الحصول على معلومات من خاصيات العنصر
</h3>

<p>
	يسهل علينا التابع <code>get()‎</code> الخاص بكائنات <code>Tag</code> الوصول إلى خاصيات العناصر، ونمرر لهذا التابع سلسلةً نصيةً باسم الخاصية <code>attribute</code> وسيعيد لنا قيمتها. لنجرب المثال الآتي على الملف <code>example.html</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7031_29" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> bs4
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> soup </span><span class="pun">=</span><span class="pln"> bs4</span><span class="pun">.</span><span class="typ">BeautifulSoup</span><span class="pun">(</span><span class="pln">open</span><span class="pun">(</span><span class="str">'example.html'</span><span class="pun">),</span><span class="pln"> </span><span class="str">'html.parser'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spanElem </span><span class="pun">=</span><span class="pln"> soup</span><span class="pun">.</span><span class="pln">select</span><span class="pun">(</span><span class="str">'span'</span><span class="pun">)[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">spanElem</span><span class="pun">)</span><span class="pln">
</span><span class="str">'&lt;span id="author"&gt;Al Sweigart&lt;/span&gt;'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spanElem</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'id'</span><span class="pun">)</span><span class="pln">
</span><span class="str">'author'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spanElem</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'some_nonexistent_addr'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">None</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spanElem</span><span class="pun">.</span><span class="pln">attrs
</span><span class="pun">{</span><span class="str">'id'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'author'</span><span class="pun">}</span></pre>

<p>
	يمكننا استخدام <code>select()‎</code> للعثور على أي عناصر <code>&lt;span&gt;</code> ثم تخزين أول عنصر مطابق في المتغير <code>spanElem</code>، الذي سنمرر للتابع <code>get()‎</code> القيمة <code>'id'</code> للحصول على قيمة المعرف الخاصة به، وهي <code>'author'</code> في مثالنا.
</p>

<h2 id="-6">
	مشروع: فتح جميع نتائج البحث
</h2>

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

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

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

<ol>
	<li>
		الحصول على عبارة البحث من سطر الأوامر
	</li>
	<li>
		الحصول على صفحة نتائج البحث
	</li>
	<li>
		فتح لسان متصفح جديد لكل نتيجة
	</li>
</ol>

<p>
	هذا يعني أن على برنامجك أن يفعل ما يلي:
</p>

<ol>
	<li>
		قراءة وسائط سطر الأوامر من <code>sys.argv</code>.
	</li>
	<li>
		الحصول على صفحة نتائج البحث عبر الوحدة <code>requests</code>.
	</li>
	<li>
		العثور على جميع روابط نتائج البحث.
	</li>
	<li>
		استدعاء الدالة <code>webbrowser.open()‎</code> لفتحها في المتصفح.
	</li>
</ol>

<p>
	لنبدأ البرمجة بفتح ملف جديد باسم <code>searchpypi.py</code> في محررنا.
</p>

<h3 id="1-1">
	الخطوة 1: الحصول على وسائط سطر الأوامر وطلب صفحة نتائج البحث
</h3>

<p>
	قبل أن نبدأ بالبرمجة، علينا أن نعرف ما هو رابط URL لصفحة نتائج البحث. انظر إلى شريط العنوان في المتصفح بعد إتمامك لعملية البحث، وسترى أن الرابط يشبه <a href="https://pypi.org/search/?q=SEARCH_TERM_HERE." ipsnoembed="true" rel="external nofollow">https://pypi.org/search/?q=SEARCH_TERM_HERE.</a> يمكننا استخدام الوحدة <code>requests</code> لتنزيل هذه الصفحة، ثم استخدام <code>BS4</code> للبحث عن الروابط في مستند HTML. يمكننا في النهاية أن نستعمل وحدة <code>webbrowser</code> لفتح تلك الروابط في ألسنة جديدة.
</p>

<p>
	يحب أن تكون الشيفرة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7031_31" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># searchpypi.py  - فتح عدة نتائج بحث.</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> requests</span><span class="pun">,</span><span class="pln"> sys</span><span class="pun">,</span><span class="pln"> webbrowser</span><span class="pun">,</span><span class="pln"> bs4
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Searching...'</span><span class="pun">)</span><span class="pln">    </span><span class="com"># عرض النص ريثما تحمل الصفحة</span><span class="pln">
res </span><span class="pun">=</span><span class="pln"> requests</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'https://pypi.org/search/?q='</span><span class="pln">
</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">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">
res</span><span class="pun">.</span><span class="pln">raise_for_status</span><span class="pun">()</span><span class="pln">

</span><span class="com"># TODO: Retrieve top search result links.</span><span class="pln">

</span><span class="com"># TODO: فتح لسان لكل نتيجة.</span></pre>

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

<h3 id="2-1">
	الخطوة 2: العثور على كل النتائج
</h3>

<p>
	ستحتاج الآن إلى وحدة <code>BS4</code> لاستخراج نتائج البحث من مستند HTML المنزل. لكن كيف يمكننا معرفة المحدد المناسب لحالتنا؟ ليس من المنطقي مثلًا البحث عن جميع عناصر <code>&lt;a&gt;</code> لوجود روابط كثيرة لا تهمنا؛ والحل هنا أن نفتح أدوات المطور في المتصفح وننظر إلى المحدد المناسب الذي سينتقي لنا الروابط التي نريدها فقط.
</p>

<p>
	بعد أن نبحث فسنجد بعض العناصر التي تشبه التالي: 
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7031_67" style=""><span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"package-snippet"</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"/project/pyautogui/"</span><span class="tag">&gt;</span></pre>

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

<p>
	لنعدل شيفرتنا إلى:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7031_33" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># searchpypi.py - Opens several google results.</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> requests</span><span class="pun">,</span><span class="pln"> sys</span><span class="pun">,</span><span class="pln"> webbrowser</span><span class="pun">,</span><span class="pln"> bs4
</span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">
</span><span class="com"># Retrieve top search result links.</span><span class="pln">
soup </span><span class="pun">=</span><span class="pln"> bs4</span><span class="pun">.</span><span class="typ">BeautifulSoup</span><span class="pun">(</span><span class="pln">res</span><span class="pun">.</span><span class="pln">text</span><span class="pun">,</span><span class="pln"> </span><span class="str">'html.parser'</span><span class="pun">)</span><span class="pln">
</span><span class="com"># فتح لسان لكل نتيجة.</span><span class="pln">
linkElems </span><span class="pun">=</span><span class="pln"> soup</span><span class="pun">.</span><span class="pln">select</span><span class="pun">(</span><span class="str">'.package-snippet'</span><span class="pun">)</span></pre>

<p>
	إذا ألقيت نظرةً إلى عناصر <code>&lt;a&gt;</code> فستجد أن جميع نتائج البحث لها الخاصية <code>class="package-snippet"‎</code> وإذا بحثنا في كامل مصدر الصفحة فسنتأكد أن الصنف <code>package-snippet</code> ليس مستخدمًا إلا لروابط نتائج البحث. لا يهمنا ما هو الصنف <code>package-snippet</code> ولا ما يفعل، وإنما يهمنا كيف سنستفيد منه لتحديد عناصر <code>&lt;a&gt;</code> التي نبحث عنها.
</p>

<p>
	لننشِئ كائن <code>BeautifulSoup</code> من صفحة HTML التي نزلناها ونستخدم المحدد <code>'‎.package-snippet'</code> لتحديد جميع عناصر <code>&lt;a&gt;</code> التي لها صنف CSS المحدد؛ ضع في ذهنك أن موقع PyPI قد يحدث واجهته الرسومية وقد تحتاج إلى استخدام محدد CSS مختلف مستقبلًا، إن حدث ذلك فمرر المحدد الجديد إلى التابع <code>soup.select()‎</code> وسيعمل البرنامج على ما يرام.
</p>

<h3 id="3-1">
	الخطوة 3: فتح نتائج البحث في المتصفح
</h3>

<p>
	لنخبر برنامجنا الآن أن يفتح لنا النتائج الأولى في متصفح الويب. أضف ما يلي إلى برنامجك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7031_35" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># searchpypi.py - فتح عدة نتائج بحث.</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> requests</span><span class="pun">,</span><span class="pln"> sys</span><span class="pun">,</span><span class="pln"> webbrowser</span><span class="pun">,</span><span class="pln"> bs4
</span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">
</span><span class="com"># فتح لسان لكل نتيجة.</span><span class="pln">
linkElems </span><span class="pun">=</span><span class="pln"> soup</span><span class="pun">.</span><span class="pln">select</span><span class="pun">(</span><span class="str">'.package-snippet'</span><span class="pun">)</span><span class="pln">
numOpen </span><span class="pun">=</span><span class="pln"> min</span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">linkElems</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="pln">numOpen</span><span class="pun">):</span><span class="pln">
    urlToOpen </span><span class="pun">=</span><span class="pln"> </span><span class="str">'https://pypi.org'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> linkElems</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">get</span><span class="pun">(</span><span class="str">'href'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Opening'</span><span class="pun">,</span><span class="pln"> urlToOpen</span><span class="pun">)</span><span class="pln">
    webbrowser</span><span class="pun">.</span><span class="pln">open</span><span class="pun">(</span><span class="pln">urlToOpen</span><span class="pun">)</span></pre>

<p>
	سيفتح البرنامج افتراضيًا أول خمسة روابط في المتصفح باستخدام الوحدة <code>webbrowser</code>، لكن قد يكون ناتج بحث المستخدم أقل من خمس نتائج، فحينها ننظر أيهما أقل، 5 أم عدد عناصر القائمة المعادة من استدعاء التابع <code>soup.select()‎</code>.
</p>

<p>
	الدالة المضمنة في بايثون <code>min()‎</code> تعيد العدد الأصغر من الوسائط الممررة إليها (والدالة <code>max()‎</code> تفعل العكس). يمكنك أن تستخدم الدالة <code>min()‎</code> لمعرفة إذا كان عدد الروابط أقل من 5 وتخزين الناتج في المتغير <code>numOpen</code>، والذي ستستفيد منه في حلقة <code>for</code> عبر <code>range(numOpen)‎</code>.
</p>

<p>
	سنستخدم الدالة <code>webbrowser.open()‎</code> في كل تكرار لحلقة <code>for</code> لفتح الرابط في المتصفح. لاحظ أن قيمة الخاصية <code>href</code> في عناصر <code>&lt;a&gt;</code> لا تحتوي على <code><a href="https://pypi.org" ipsnoembed="true" rel="external nofollow">https://pypi.org</a></code> لذا علينا إضافتها بأنفسنا إلى قيمة الخاصية <code>href</code> قبل فتح الرابط.
</p>

<p>
	يمكنك الآن فتح أول 5 نتائج بحث عن <code>«boring stuff»</code> في محرك بحث PyPI بكتابة الأمر searchpypi boring stuff في سطر الأوامر.
</p>

<h3 id="-7">
	أفكار لبرامج مشابهة
</h3>

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

<ul>
	<li>
		فتح جميع صفحات المنتجات في متجر أمازون بعد البحث عن منتج معين.
	</li>
	<li>
		فتح كل روابط المراجعات لمنتج ما.
	</li>
	<li>
		فتح الصور الناتجة بعد إجراء عملية بحث سريعة على أحد مواقع الصور مثل Flickr.
	</li>
</ul>

<h2 id="xkcd">
	مشروع: تنزيل كل رسمات XKCD
</h2>

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

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

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

<p>
	هذا ما سيفعله برنامجنا:
</p>

<ol>
	<li>
		فتح صفحة XKCD الرئيسية
	</li>
	<li>
		حفظ صورة الكوميكس في تلك الصفحة
	</li>
	<li>
		الانتقال إلى صفحة الكوميكس السابق
	</li>
	<li>
		تكرار العملية حتى الوصول إلى أول صورة كوميكس.
	</li>
</ol>

<p>
	هذا يعني أن الشيفرة البرمجية ستفعل ما يلي:
</p>

<ol>
	<li>
		تنزيل الصفحات باستخدام الوحدة <code>requests</code>.
	</li>
	<li>
		العثور على رابط URL لصورة الكوميكس باستخدام وحدة <code>BS4</code>.
	</li>
	<li>
		تنزيل وحفظ صورة الكوميكس إلى نظام الملفات باستخدام <code>iter_content()‎</code>.
	</li>
	<li>
		العثور على رابط صورة الكوميكس السابقة، وتكرار العملية كلها.
	</li>
</ol>

<p>
	افتح ملفًا جديدًا في محررك وسمِّه باسم <code>downloadXkcd.py</code>.
</p>

<h3 id="1-2">
	الخطوة 1: تصميم البرنامج
</h3>

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

<ul>
	<li>
		رابط URL لملف صورة الكوميكس في الخاصية <code>href</code> في <a href="https://wiki.hsoub.com/HTML/img" rel="external">العنصر &lt;img&gt;</a>.
	</li>
	<li>
		العنصر <code>&lt;img&gt;</code> موجود داخل العنصر <code>&lt;div id="comic"‎&gt;</code>.
	</li>
	<li>
		الزر <code>Perv</code> له الخاصية <code>rel</code> وقيمتها <code>prev</code>.
	</li>
	<li>
		صفحة أول صورة كوميكس يشير فيها الزر <code>Prev</code> إلى الرابط <code><a href="https://xkcd.com/#" ipsnoembed="false" rel="external nofollow">https://xkcd.com/#</a></code> مما يشير إلى عدم وجود صفحات سابقة. عدّل الشيفرة لتبدو كما يلي:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7031_37" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># downloadXkcd.py - تنزيل كل صورة كوميكس في XKCD.</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> requests</span><span class="pun">,</span><span class="pln"> os</span><span class="pun">,</span><span class="pln"> bs4

url </span><span class="pun">=</span><span class="pln"> </span><span class="str">'https://xkcd.com'</span><span class="pln">               </span><span class="com"># starting url</span><span class="pln">
os</span><span class="pun">.</span><span class="pln">makedirs</span><span class="pun">(</span><span class="str">'xkcd'</span><span class="pun">,</span><span class="pln"> exist_ok</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">)</span><span class="pln">    </span><span class="com"># store comics in ./xkcd</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> url</span><span class="pun">.</span><span class="pln">endswith</span><span class="pun">(</span><span class="str">'#'</span><span class="pun">):</span><span class="pln">
    </span><span class="com"># TODO: Download the page.</span><span class="pln">

    </span><span class="com"># TODO: Find the URL of the comic image.</span><span class="pln">

    </span><span class="com"># TODO: Download the image.</span><span class="pln">

    </span><span class="com"># TODO: حفظ الصورة إلى ./xkcd.</span><span class="pln">

    </span><span class="com"># TODO: الحصول على رابط الصفحة السابقة.</span><span class="pln">

</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Done.'</span><span class="pun">)</span></pre>

<p>
	سيكون لدينا متغير اسمه <code>url</code> يبدأ بالقيمة <code>'https://xkcd.com'</code> وتحدث قيمته دوريًا ضمن حلقة <code>for</code> لتصبح الرابط الموجود في الزر <code>Prev</code> للصفحة الحالية. وسننزل صورة الكوميكس في كل تكرار من تكرارات حلقة <code>for</code> الموجودة في الرابط url، وسننتهي من حلقة التكرار حينما تنتهي قيمة url بالعلامة <code>'#'</code>.
</p>

<p>
	سننزل ملفات الصور إلى مجلد موجود في مجلد العمل الحالي باسم <code>xkcd</code>، وسنتأكد من أن المجلد موجود باستدعاء <code>os.makedirs()‎</code> مع تمرير وسيط الكلمات المفتاحية <code>exist_ok=True</code> الذي يمنع الدالة من رمي استثناء إن كان المجلد موجودًا مسبقًا. بقية الشيفرة هو تعليقات سنملؤها في الأقسام القادمة.
</p>

<h3 id="2-2">
	الخطوة 2: تنزيل صفحة الويب
</h3>

<p>
	لنكتب الشيفرة الآتية التي ستنزل الصفحة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7031_39" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># downloadXkcd.py - تنزيل كل صورة كوميكس في XKCD.</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> requests</span><span class="pun">,</span><span class="pln"> os</span><span class="pun">,</span><span class="pln"> bs4

url </span><span class="pun">=</span><span class="pln"> </span><span class="str">'https://xkcd.com'</span><span class="pln">               </span><span class="com"># starting url</span><span class="pln">
os</span><span class="pun">.</span><span class="pln">makedirs</span><span class="pun">(</span><span class="str">'xkcd'</span><span class="pun">,</span><span class="pln"> exist_ok</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">)</span><span class="pln">    </span><span class="com"># store comics in ./xkcd</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> url</span><span class="pun">.</span><span class="pln">endswith</span><span class="pun">(</span><span class="str">'#'</span><span class="pun">):</span><span class="pln">
    </span><span class="com"># Download the page.</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Downloading page %s...'</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> url</span><span class="pun">)</span><span class="pln">
    res </span><span class="pun">=</span><span class="pln"> requests</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">url</span><span class="pun">)</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">raise_for_status</span><span class="pun">()</span><span class="pln">

    soup </span><span class="pun">=</span><span class="pln"> bs4</span><span class="pun">.</span><span class="typ">BeautifulSoup</span><span class="pun">(</span><span class="pln">res</span><span class="pun">.</span><span class="pln">text</span><span class="pun">,</span><span class="pln"> </span><span class="str">'html.parser'</span><span class="pun">)</span><span class="pln">

    </span><span class="com"># TODO: Find the URL of the comic image.</span><span class="pln">

    </span><span class="com"># TODO: Download the image.</span><span class="pln">

    </span><span class="com"># TODO: حفظ الصورة إلى ./xkcd.</span><span class="pln">

    </span><span class="com"># TODO: الحصول على رابط الصفحة السابقة.</span><span class="pln">

</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Done.'</span><span class="pun">)</span></pre>

<p>
	لنطبع بدايةً قيمة url ليعرف المستخدم ما هو رابط URL الذي يحاول البرنامج تنزيله، ثم سنستخدم الدالة <code>requests.get()‎</code> في الوحدة <code>requests</code> لتنزيل الصفحة. ثم سنستدعي التابع <code>raise_for_status()‎</code> كالعادة لرمي استثناء إن حدثت مشكلة ما في التنزيل؛ ثم إن سارت الأمور على ما يرام فسننشِئ كائن <code>BeautifulSoup</code> من نص الصفحة المنزلة.
</p>

<h3 id="3-2">
	الخطوة 3: البحث عن صورة الكوميكس وتنزيلها
</h3>

<p>
	لنعدل شيفرة برنامجنا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7031_41" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># downloadXkcd.py - تنزيل كل صورة كوميكس في XKCD.</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> requests</span><span class="pun">,</span><span class="pln"> os</span><span class="pun">,</span><span class="pln"> bs4

</span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">

    </span><span class="com"># Find the URL of the comic image.</span><span class="pln">
    comicElem </span><span class="pun">=</span><span class="pln"> soup</span><span class="pun">.</span><span class="pln">select</span><span class="pun">(</span><span class="str">'#comic img'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> comicElem </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="str">'Could not find comic image.'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
        comicUrl </span><span class="pun">=</span><span class="pln"> </span><span class="str">'https:'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> comicElem</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">get</span><span class="pun">(</span><span class="str">'src'</span><span class="pun">)</span><span class="pln">
        </span><span class="com"># Download the image.</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Downloading image %s...'</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">comicUrl</span><span class="pun">))</span><span class="pln">
        res </span><span class="pun">=</span><span class="pln"> requests</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">comicUrl</span><span class="pun">)</span><span class="pln">
        res</span><span class="pun">.</span><span class="pln">raise_for_status</span><span class="pun">()</span><span class="pln">

    </span><span class="com"># TODO: حفظ الصورة إلى ./xkcd.</span><span class="pln">

    </span><span class="com"># TODO: الحصول على رابط الصفحة السابقة.</span><span class="pln">

</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Done.'</span><span class="pun">)</span></pre>

<p>
	بعد تفحص صفحة XKCD عبر أدوات المطور، سنعرف أن عنصر <code>&lt;img&gt;</code> لصورة الكوميكس موجود داخل عنصر <code>&lt;div&gt;</code> له الخاصية <code>id</code> التي قيمتها هي <code>comic</code>، وبالتالي سيكون المحدد <code>'‎#comic img'</code> صحيحًا لتحديد العنصر <code>&lt;img&gt;</code> عبر كائن <code>BeautifulSoup</code>.
</p>

<p>
	تمتلك بعض صفحات موقع XKCD على محتوى خاص لا يمثل صورة بسيطة، لكن لا بأس فيمكننا تخطي تلك الصفحات، فإن لم يطابِق المحدد الخاص بنا أي عنصر فسيعيد استدعاء <code>soup.select('#comic img')‎</code> قائمة فارغة، وحينها سيظهر برنامجنا رسالة خطأ ويتجاوز الصفحة دون تنزيل الصورة.
</p>

<p>
	عدا ذلك، فسيعيد المحدد السابق قائمةً فيها عنصر <code>&lt;img&gt;</code> وحيد، ويمكننا الحصول على قيمة الخاصية <code>src</code> لعنصر <code>&lt;img&gt;</code>ونمررها إلى <code>requests.get()‎</code> لتنزيل صورة الكوميكس.
</p>

<h3 id="4">
	الخطوة 4: حفظ الصورة والعثور على الصفحة السابقة
</h3>

<p>
	لنعدل الشيفرة لتصبح كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7031_43" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># downloadXkcd.py - تنزيل كل صورة كوميكس في XKCD.</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> requests</span><span class="pun">,</span><span class="pln"> os</span><span class="pun">,</span><span class="pln"> bs4

</span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">

        </span><span class="com"># حفظ الصورة إلى ./xkcd.</span><span class="pln">
        imageFile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="pln">os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="str">'xkcd'</span><span class="pun">,</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">basename</span><span class="pun">(</span><span class="pln">comicUrl</span><span class="pun">)),</span><span class="pln">
</span><span class="str">'wb'</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> chunk </span><span class="kwd">in</span><span class="pln"> res</span><span class="pun">.</span><span class="pln">iter_content</span><span class="pun">(</span><span class="lit">100000</span><span class="pun">):</span><span class="pln">
            imageFile</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">chunk</span><span class="pun">)</span><span class="pln">
        imageFile</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">
    prevLink </span><span class="pun">=</span><span class="pln"> soup</span><span class="pun">.</span><span class="pln">select</span><span class="pun">(</span><span class="str">'a[rel="prev"]'</span><span class="pun">)[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
    url </span><span class="pun">=</span><span class="pln"> </span><span class="str">'https://xkcd.com'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> prevLink</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'href'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Done.'</span><span class="pun">)</span></pre>

<p>
	أصبح لدينا ملف صورة الكوميكس مخزنًا في المتغير <code>res</code>، وعلينا كتابة بيانات هذه الصورة إلى ملف في نظام الملفات المحلي لدينا. سنحدد اسم الملف المحلي للصورة ونمرره إلى الدالة <code>open()‎</code>، لاحظ أن المتغير <code>comicUrl</code> يحتوي على قيمة تشبه القيمة الآتية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_357_40" style=""><span class="pln"> </span><span class="str">'https://imgs.xkcd.com/comics/heartbleed_explanation.png'</span></pre>

<p>
	ويبدو أنك لاحظت وجود مسار الملف فيها.
</p>

<p>
	يمكنك استخدام الدالة <code>os.path.basename()‎</code> مع <code>comicUrl</code> لإعادة آخر جزء من رابط URL السابق، أي <code>'heartbleed_explanation.png'</code>، ويمكنك حينها استخدام هذا الاسم حين حفظ الصورة إلى نظام الملفات المحلي.
</p>

<p>
	يمكنك أن تضيف هذا الاسم إلى اسم مجلد xkcd باستخدام الدالة <code>os.path.join()‎</code> كما تعلمنا سابقًا لكي يستخدم برنامجك الفاصل الصحيح (الخط المائل الخلفي <code>\</code> في ويندوز، والخط المائل / في لينكس وماك). أصبح لدينا الآن اسم ملف صحيح، ويمكننا استدعاء الدالة <code>open()‎</code> لفتح ملف جديد بوضع الكتابة الثنائية <code>'wb'</code>.
</p>

<p>
	إذا كنت تذكر حينما حفظنا الملفات التي نزلناها عبر الوحدة <code>requests</code> في بداية المقال كنا نمر بحلقة تكرار على القيمة المعادة من التابع <code>iter_content()‎</code>، وستكتب الشيفرة الموجودة في حلقة <code>for</code> قطعًا من بيانات الصورة (كحد أقصى 100,000 بايت كل مرة) إلى الملف، ثم تغلق الملف. أصبحت الصورة محفوظة لديك محليًا الآن!
</p>

<p>
	علينا بعدئذٍ استخدام المحدد <code>'a[rel="prev"]‎'</code> لتحديد العنصر <code>&lt;a&gt;</code> الذي له العلاقة <code>rel</code> مضبوطةً إلى <code>prev</code>. يمكنك استخدام قيمة الخاصية <code>href</code> لعنصر <code>&lt;a&gt;</code> المحدد للحصول على رابط صورة الكوميكس السابقة، والتي ستخزن في المتغير <code>url</code>، ثم ستدور <a href="https://wiki.hsoub.com/Python#while" rel="external">حلقة while</a> مرة أخرى وتعيد تنفيذ عملية التنزيل من جديد على الصفحة الجديدة.
</p>

<p>
	سيبدو ناتج تنفيذ البرنامج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_7031_49">Downloading page https://xkcd.com...
Downloading image https://imgs.xkcd.com/comics/phone_alarm.png...
Downloading page https://xkcd.com/1358/...
Downloading image https://imgs.xkcd.com/comics/nro.png...
Downloading page https://xkcd.com/1357/...
Downloading image https://imgs.xkcd.com/comics/free_speech.png...
Downloading page https://xkcd.com/1356/...
Downloading image https://imgs.xkcd.com/comics/orbital_mechanics.png...
Downloading page https://xkcd.com/1355/...
Downloading image https://imgs.xkcd.com/comics/airplane_message.png...
Downloading page https://xkcd.com/1354/...
Downloading image https://imgs.xkcd.com/comics/heartbleed_explanation.png...
--snip–</pre>

<p>
	هذا المشروع هو مثال ممتاز لبرامج تتبع الروابط تلقائًا لاستخراج كمية معلومات كبيرة من الويب. يمكنك تعلم المزيد من المعلومات حول ميزات <code>Beautiful Soup</code> الأخرى من توثيقها الرسمي.
</p>

<h3 id="-8">
	أفكار لبرامج مشابهة
</h3>

<p>
	تنزيل صفحات الويب وتتبع الروابط فيها هو أساس أي برنامج زحف crawler. يمكنك أن تبرمج برامج تفعل ما يلي:
</p>

<ul>
	<li>
		تنسخ موقعًا كاملًا احتياطيًا.
	</li>
	<li>
		تنسخ جميع التعليقات من أحد المنتديات.
	</li>
	<li>
		تعرض قائمة بجميع المنتجات التي عليها تخفيضات في أحد المتاجر.
	</li>
</ul>

<p>
	الوحدتان <code>requests</code> و <code>bs4</code> رائعتين جدًا، لكن عليك أن تعرف ما هو رابط URL المناسب لتمريره إلى <code>requests.get()‎</code>، لكن في بعض الأحيان قد لا يكون ذلك سهلًا؛ أو ربما عليك تسجيل الدخول إلى أحد المواقع قبل بدء عملية الاستخراج، لهذا السبب سنستكشف سويةً الوحدة <code>selenium</code> لأداء مهام معقدة.
</p>

<h2 id="selenium">
	التحكم في المتصفح عبر الوحدة selenium
</h2>

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

<p>
	لكن إن كان علينا التعامل مع صفحات الويب بطريقة تعتمد على <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="">شيفرات JavaScript</a> التي تحدث الصفحة، فعلينا استخدام <code>selenium</code> بدلًا من <code>requests</code>. أضف إلى ذلك أن المواقع الشهيرة مثل أمازون تستخدم برمجيات للتعرف على الزيارات الآتية من سكربتات التي تحاول استخراج البيانات من صفحاتها أو إنشاء عدّة حسابات مجانية، ومن المرجح أن تحجب هذه المواقع برامجك بعد فترة؛ وهنا تأتي الوحدة <code>selenium</code> التي تعمل مثل متصفحات الويب العادية.
</p>

<p>
	أحد أشهر العلامات التي تتعرف فيها المواقع أن الزيارات آتية من برنامج (أو سكربت script) هي عبارة <code>user-agent</code>، التي تُعرِّف متصفح الويب المستخدم وتضمَّن في كل طلبيات HTTP. فمثلًا تكون عبارة <code>user-agent</code> للوحدة <code>requests</code> شيء يشبه <code>'python-requests/2.21.0'</code>.
</p>

<p>
	يمكنك زيارة موقع مثل <a href="https://www.whatsmyua.info/" rel="external nofollow">whatsmyua.info</a> لتعرف ما هي <code>user-agent</code> الخاصة بك. أما الوحدة <code>selenium</code> فمن المرجح أن تظن المواقع أنها مستخدم بشري، لأنها تستخدم user-agent شبيه بالمتصفحات العادية مثل:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7031_69" style=""><span class="pln">Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:124.0) Gecko/20100101 Firefox/124.0 </span></pre>

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

<h3 id="selenium-1">
	تشغيل متصفح تتحكم فيه selenium
</h3>

<p>
	سنرى في الأمثلة القادمة كيفية التحكم في متصفح فيرفكس من <code>selenium</code>، إذا لم يكن مثبتًا لديك فيمكنك تنزيله من <a href="https://getfirefox.com/" rel="external nofollow">getfirefox.com</a>، ويمكنك تثبيت <code>selenium</code>،من سطر الأوامر بتشغيل <code>pip install --user selenium</code>، وأذكرك بالذهاب إلى الملحق أ لمزيد من المعلومات.
</p>

<p>
	قد يكون استيراد مكونات <code>selenium</code> مختلفًا عليك، فبدلًا من <code>import selenium</code> سنستعمل <code>from selenium import webdriver</code> (سبب فعل <code>selenium</code> لذلك خارج نطاق هذه السلسلة لا تقلق حوله). يمكنك بعد ذلك تشغيل فايرفوكس مع <code>selenium</code> بكتابة ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7031_47" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> selenium </span><span class="kwd">import</span><span class="pln"> webdriver
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> browser </span><span class="pun">=</span><span class="pln"> webdriver</span><span class="pun">.</span><span class="typ">Firefox</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> type</span><span class="pun">(</span><span class="pln">browser</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="kwd">class</span><span class="pln"> </span><span class="str">'selenium.webdriver.firefox.webdriver.WebDriver'</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> browser</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'https://inventwithpython.com'</span><span class="pun">)</span></pre>

<p>
	ستلاحظ أن متصفح فايرفوكس قد بدأ بالعمل حين استدعاء <code>webdriver.Firefox()‎</code>. استدعاء <code>type()‎</code> على <code>webdriver.Firefox()‎</code> سيظهر أنها من نوع البيانات <code>WebDrive</code>، واستدعاء التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_357_44" style=""><span class="pln"> browser</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'https://inventwithpython.com'</span><span class="pun">)‎</span><span class="pln"> </span></pre>

<p>
	سيوجه المتصفح إلى <code><a href="https://inventwithpython.com/" ipsnoembed="true" rel="external nofollow">https://inventwithpython.com/</a></code>.
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="153637" data-ratio="61.67" data-unique="21w9zhtus" width="694" alt="بعد استدعاء webdriver.Firefox()_ و get()_ ستفتح الصفحة في متصفح فايرفوكس.jpg" src="https://academy.hsoub.com/uploads/monthly_2024_07/webdriver.Firefox()_get()_.jpg.93f20ae1a36f5a4b6eb7f7eaeffb12e3.jpg">
</p>

<p style="text-align: center;">
	بعد استدعاء <code>webdriver.Firefox()‎</code> و <code>get()‎</code> ستفتح الصفحة في متصفح فايرفوكس
</p>

<p>
	إذا واجهت مشكلة من قبيل <code>‎'geckodriver' executable needs to be in PATH</code> فهذا يعني أن عليك تنزيل محرك فايرفوكس يدويًا قبل استخدام <code>selenium</code> للتحكم به. يمكنك التحكم بمتصفحات أخرى غير فيرفكس إذا ثبتت محرك الويب لهم <code>webdriver</code>.
</p>

<p>
	لمتصفح فايرفوكس، اذهب إلى <a href="https://github.com/mozilla/geckodriver/releases" rel="external nofollow">github.com</a> وثبت محرك geckodriver لنظام تشغيلك. (كلمة «Gecko» هي اسم محرك المتصفح engine في فيرفكس). سيحتوي الملف المضغوط المنزل على <code>geckodriver.exe</code> في ويندوز أو geckodriver في ماك ولينكس، وعليك وضعه في مسار PATH الخاص في نظامك، راجع الإجابة الآتية <a href="https://stackoverflow.com/q/40208051/1893164" rel="external nofollow">stackoverflow.com</a>.
</p>

<p>
	أما لمتصفح كروم فاذهب إلى <a href="https://sites.google.com/a/chromium.org/chromedriver/downloads" rel="external nofollow">chromium.org</a> ونزل الملف المضغوط المناسب لنظامك، وضع الملف chromedriver.exe أو chromedriver في مسار PATH كما ذكرنا أعلاه.
</p>

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

<p>
	قد تواجه مشاكل في تشغيل المتصفحات الجديدة في <code>selenium</code>، بسبب عدم التوافقية بينهما، لكن يمكنك إجراء حل التفافي بتثبيت نسخة قديمة من المتصفح أو من وحدة <code>selenium</code>. يمكنك معرفة تاريخ الإصدارات من <a href="https://pypi.org/project/selenium/#history" rel="external nofollow">pypi.org</a>. للأسف قد تحدث مشاكل توافقية بين <code>selenium</code> وبعض إصدارات المتصفحات، وأنصحك حينها بالبحث في الويب عن الحلول المقترحة، وراجع الملحق أ لمعلومات حول تثبيت إصدار محدد من <code>selenium</code> (مثل تثبيت <code>pip install --user -U selenium==3.14.1</code>).
</p>

<h3 id="-9">
	العثور على عناصر في الصفحة
</h3>

<p>
	توفر كائنات <code>WebDriver</code> عددًا من التوابع للعثور على عناصر صفحة، ويمكن تقسيمها إلى قسمين من التوابع <code>find_element_‎</code> و <code>find_elements_*‎</code>. توابع <code>find_element_*‎</code> تعيد كائن <code>WebElement</code> وحيد يمثل أول عنصر في الصفحة يطابق الطلبية التي حددتها، بينما تعيد توابع <code>_find_elements‎</code> قائمة من كائنات <code>WebElement_*‎</code> لكل عنصر مطابق في الصفحة.
</p>

<p>
	يظهر الجدول الموالي أمثلة على التوابع <code>find_element_‎</code> و <code>find_elements_‎</code> المستدعاة على كائن <code>WebDriver</code> مخزن في المتغير <code>browser</code>.
</p>

<table>
	<thead>
		<tr>
			<th>
				اسم التابع
			</th>
			<th>
				كائن/قائمة كائنات WebElement
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				browser.find<code>_</code>element<code>_</code>by<code>_</code>class<code>_</code>name(name) browser.find<code>_</code>elements<code>_</code>by<code>_</code>class<code>_</code>name(name)
			</td>
			<td>
				العناصر التي تستخدم صنف CSS باسم name
			</td>
		</tr>
		<tr>
			<td>
				browser.find<code>_</code>element<code>_</code>by<code>_</code>css<code>_</code>selector(selector) browser.find<code>_</code>elements<code>_</code>by<code>_</code>css<code>_</code>selector(selector)
			</td>
			<td>
				العناصر التي تطابق محدد CSS معين
			</td>
		</tr>
		<tr>
			<td>
				browser.find<code>_</code>element<code>_</code>by<code>_</code>id(id) browser.find<code>_</code>elements<code>_</code>by<code>_</code>id(id)                             
			</td>
			<td>
				العناصر التي تطابق id معين
			</td>
		</tr>
		<tr>
			<td>
				<p>
					browser.find<code>_</code>element<code>_</code>by<code>_</code>link<code>_</code>text(text) browser.find<code>_</code>elements<code>_</code>by<code>_</code>link<code>_</code>text(text)
				</p>
			</td>
			<td>
				عناصر <code>&lt;a&gt;</code> التي يطابق محتواها القيمة text كاملةً
			</td>
		</tr>
		<tr>
			<td>
				browser.find<code>_</code>element<code>_</code>by<code>_</code>partial<code>_</code>link<code>_</code>text(text) browser.find<code>_</code>elements<code>_</code>by<code>_</code>partial<code>_</code>link<code>_</code>text(text)
			</td>
			<td>
				عناصر <code>&lt;a&gt;</code> التي يطابق محتواها القيمة text جزئيًا
			</td>
		</tr>
		<tr>
			<td>
				browser.find<code>_</code>element<code>_</code>by<code>_</code>name(name) browser.find<code>_</code>elements<code>_</code>by<code>_</code>name(name)
			</td>
			<td>
				العناصر التي لها الخاصية <code>name</code> وتطابق قيمة معينة
			</td>
		</tr>
		<tr>
			<td>
				browser.find<code>_</code>element<code>_</code>by<code>_</code>tag<code>_</code>name(name) browser.find<code>_</code>elements<code>_</code>by<code>_</code>tag<code>_</code>name(name)
			</td>
			<td>
				العناصر التي تطابق وسمًا معينًا، وهي غير حساسة لحالة الأحرف (أي <code>&lt;a&gt;</code> يمكن أن يطابق عبر 'a' أو 'A')
			</td>
		</tr>
	</tbody>
</table>

<p style="text-align: center;">
	توابع <code>WebDriver</code> للعثور على العناصر في <code>selenium</code>
</p>

<p>
	باستثناء التوابع <code>‎*_by_tag_name()</code>‎ تكون جميع الوسائط الممررة إلى الدوال حساسةً لحالة الأحرف، وإذا لم تكن العناصر موجودة في الصفحة فستطلق <code>selenium</code> الاستثناء <code>NoSuchElement</code>، وعليك استخدام عبارات <code>try</code> و <code>except</code> إذا لم ترغب بتوقف برنامج عن العمل عند ذلك.
</p>

<p>
	بعد أن تحصل على كائن <code>WebElement</code> فيمكنك أن تتعرف على المزيد حوله بقراءة سماته أو استدعاء توابع المذكورة في الجدول التالي:
</p>

<table>
	<thead>
		<tr>
			<th>
				السمة أو التابع
			</th>
			<th>
				الوصف
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				tag_name
			</td>
			<td>
				اسم الوسم، مثل <code>'a'</code> لعنصر <code>&lt;a&gt;</code>
			</td>
		</tr>
		<tr>
			<td>
				get_attribute(name)
			</td>
			<td>
				قيمة خاصية <code>name</code> للعنصر
			</td>
		</tr>
		<tr>
			<td>
				text
			</td>
			<td>
				النص الموجود داخل العنصر، مثل <code>'hello'</code> في <code>&lt;span&gt;hello&lt;/span&gt;</code>
			</td>
		</tr>
		<tr>
			<td>
				clear()
			</td>
			<td>
				مسح النص المكتوب في الحقول النصية
			</td>
		</tr>
		<tr>
			<td>
				is_displayed()
			</td>
			<td>
				إعادة <code>True</code> إذا كان العنصر ظاهرًا، وإلا فيعيد <code>False</code>
			</td>
		</tr>
		<tr>
			<td>
				is_enabled()
			</td>
			<td>
				إعادة <code>True</code> إذا كان حقل الإدخال مفعلًا، وإلا فيعيد <code>False</code>
			</td>
		</tr>
		<tr>
			<td>
				is_selected()
			</td>
			<td>
				لأزرار الانتقاء radio ومربعات التأشير checkbox ستعيد <code>True</code> إذا كان العنصر مختار، وإلا فتعيد <code>False</code>
			</td>
		</tr>
		<tr>
			<td>
				location
			</td>
			<td>
				قاموس فيه المفاتيح <code>'x'</code> و <code>'y'</code> لمكان العنصر في الصفحة
			</td>
		</tr>
	</tbody>
</table>

<p style="text-align: center;">
	سمات وتوابع الكائن <code>WebElement</code>
</p>

<p>
	مثلًا، افتح ملفًا جديدًا واكتب البرنامج الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7031_51" style=""><span class="kwd">from</span><span class="pln"> selenium </span><span class="kwd">import</span><span class="pln"> webdriver
browser </span><span class="pun">=</span><span class="pln"> webdriver</span><span class="pun">.</span><span class="typ">Firefox</span><span class="pun">()</span><span class="pln">
browser</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'https://inventwithpython.com'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
    elem </span><span class="pun">=</span><span class="pln"> browser</span><span class="pun">.</span><span class="pln">find_element_by_class_name</span><span class="pun">(</span><span class="str">' cover-thumb'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Found &lt;%s&gt; element with that class name!'</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">tag_name</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="str">'Was not able to find an element with that name.'</span><span class="pun">)</span></pre>

<p>
	فتحنا هنا متصفح فيرفكس ووجهناه إلى رابط URL معين، وحاولنا العثور على العناصر التي لها الصنف <code>bookcover</code>، وإذا عثرنا على أحد العناصر فسنطبع اسم الوسم عبر السمة <code>tag_name</code>؛ أما لو لم يعثر على أي عنصر فسنطبع رسالة مختلفة. سيعيد البرنامج الناتج الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7031_53" style=""><span class="typ">Found</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">img</span><span class="pun">&gt;</span><span class="pln"> element </span><span class="kwd">with</span><span class="pln"> that </span><span class="kwd">class</span><span class="pln"> name</span><span class="pun">!</span></pre>

<p>
	أي عثرنا على عنصر <code>&lt;img&gt;</code> له اسم الصنف <code>'bookcover'</code>.
</p>

<h3 id="-10">
	الضغط على عناصر الصفحة
</h3>

<p>
	تمتلك كائنات <code>WebElement</code> المعادة من التوابع <code>find_element_*‎</code> و <code>find_elements_*‎</code> التابع <code>click()‎</code> الذي يحاكي ضغطات الفأرة على العنصر، ويمكن استخدام هذا التابع للضغط على رابط أو تحديد زر انتقاء أو الضغط على زر الإرسال أو أي حدث آخر يُطلَق عند الضغط على أحد العناصر. جرب المثال الآتي في الطرفية التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7031_56" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> selenium </span><span class="kwd">import</span><span class="pln"> webdriver
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> browser </span><span class="pun">=</span><span class="pln"> webdriver</span><span class="pun">.</span><span class="typ">Firefox</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> browser</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'https://inventwithpython.com'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> linkElem </span><span class="pun">=</span><span class="pln"> browser</span><span class="pun">.</span><span class="pln">find_element_by_link_text</span><span class="pun">(</span><span class="str">'Read Online for Free'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> type</span><span class="pun">(</span><span class="pln">linkElem</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="kwd">class</span><span class="pln"> </span><span class="str">'selenium.webdriver.remote.webelement.FirefoxWebElement'</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> linkElem</span><span class="pun">.</span><span class="pln">click</span><span class="pun">()</span><span class="pln"> </span><span class="com"># follows the "Read Online for Free" link</span></pre>

<p>
	سيفتح متصفح فيرفكس الصفحة ويحصل على العنصر <code>&lt;a&gt;</code> الذي يحتوي على النص Read it Online ويحاكي الضغط على الرابط كما لو ضغطته بنفسك.
</p>

<h3 id="-11">
	تعبئة وإرسال الاستمارات
</h3>

<p>
	يمكن تعبئة الحقول النصية مثل <code>&lt;input&gt;</code> أو <code><a href="https://wiki.hsoub.com/HTML/textarea" rel="external">&lt;textarea&gt;</a></code> بالبحث عنها ثم استدعاء التابع <code>send_keys()‎</code>. جرب ما يلي في الطرفية التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7031_58" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> selenium </span><span class="kwd">import</span><span class="pln"> webdriver
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> browser </span><span class="pun">=</span><span class="pln"> webdriver</span><span class="pun">.</span><span class="typ">Firefox</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> browser</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'https://login.metafilter.com'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> userElem </span><span class="pun">=</span><span class="pln"> browser</span><span class="pun">.</span><span class="pln">find_element_by_id</span><span class="pun">(</span><span class="str">'user_name)
&gt;&gt;&gt; userElem.send_keys('</span><span class="pln">your_real_username_here</span><span class="str">')


&gt;&gt;&gt; passwordElem = browser.find_element_by_id('</span><span class="pln">user_pass</span><span class="str">')
&gt;&gt;&gt; passwordElem.send_keys('</span><span class="pln">your_real_password_here</span><span class="str">')
&gt;&gt;&gt; passwordElem.submit()</span></pre>

<p>
	لطالما لم تغيّر صفحة MetaFilter المعرف <code>id</code> لحقول اسم المستخدم وكلمة المرور بعد نشر هذا الكتاب، فيمكنك استخدام الشيفرة السابقة لملء تلك الحقول النصية (تذكر أنك تستطيع استخدام أدوات المطور للتأكد من المعرف <code>id</code> للحقول في أي وقت).
</p>

<p>
	استدعاء التابع <code>submit()‎</code> على أي عنصر في الاستمارة له نفس تأثير الضغط على زر الإرسال.
</p>

<p>
	تحذير: ابتعد عن تخزين كلمات المرور الخاصة بك في الشيفرة المصدرية لبرامجك قدر الإمكان، فمن السهل تسريب كلمات المرور إذا تركناها دون تشفير. يمكن لبرنامجك أن يطلب كلمة المرور من المستخدم أثناء التشغيل كما ناقشنا في <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%AA%D8%AD%D9%82%D9%82-%D9%85%D9%86-%D8%A7%D9%84%D9%85%D8%AF%D8%AE%D9%84%D8%A7%D8%AA-%D8%B9%D8%A8%D8%B1-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2346/" rel="">مقال سابق</a>.
</p>

<h3 id="-12">
	إرسال المفاتيح الخاصة
</h3>

<p>
	تمتلك <code>selenuim</code> وحدةً للمفاتيح الخاصة التي لا يمكن كتابتها كسلسلة نصية، مثل زر Tab أو الأسهم. تلك القيم مخزنة كسمات في الوحدة <code>selenium.webdriver.common.keys</code>، ولأن اسم الوحدة طويل جدًا فمن الأسهل كتابة <code>from selenium.webdriver.common.keys import Keys</code> في بداية البرنامج، وحينها تستطيع استخدام Keys في أي مكان تريد أن تكتب فيه <code>selenium.webdriver.common.keys</code>. يعرض الجدول 12-5 أشهر القيم المستخدمة.
</p>

<p>
	الجدول 12-5: أشهر القيم المستخدمة في الوحدة <code>selenium.webdriver.common.keys</code>.
</p>

<table>
	<thead>
		<tr>
			<th>
				السمة
			</th>
			<th>
				الشرح
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				Keys.DOWN و Keys.UP و Keys.LEFT و Keys.RIGHT
			</td>
			<td>
				الأسهم في لوحة المفاتيح
			</td>
		</tr>
		<tr>
			<td>
				Keys.ENTER و Keys.RETURN
			</td>
			<td>
				زر Enter
			</td>
		</tr>
		<tr>
			<td>
				Keys.HOME و Keys.END و Keys.PAGE_DOWN و Keys.PAGE_UP
			</td>
			<td>
				أزرار Home و End و PageDown و PageUp على التوالي
			</td>
		</tr>
		<tr>
			<td>
				Keys.ESCAPE و Keys.BACK_SPACE و Keys.DELETE
			</td>
			<td>
				أزرار Escape و Backspace و Delete على التوالي
			</td>
		</tr>
		<tr>
			<td>
				Keys.F1 و Keys.F2 و . . . و Keys.F12
			</td>
			<td>
				الأزرار F1 حتى F12 في الصف العلوي من لوحة المفاتيح
			</td>
		</tr>
		<tr>
			<td>
				Keys.TAB
			</td>
			<td>
				زر Tab
			</td>
		</tr>
	</tbody>
</table>

<p>
	فمثلًا لو لم يكن المؤشر موجودًا داخل حقل نصي، فالضغط على زر Home و End سيؤدي إلى التمرير إلى بداية ونهاية الصفحة على التوالي. جرب ما يلي على الصدفة التفاعلية ولاحظ كيف يؤدي استدعاء <code>send_keys()‎</code> إلى تمرير الصفحة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7031_60" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> selenium </span><span class="kwd">import</span><span class="pln"> webdriver
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> selenium</span><span class="pun">.</span><span class="pln">webdriver</span><span class="pun">.</span><span class="pln">common</span><span class="pun">.</span><span class="pln">keys </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Keys</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> browser </span><span class="pun">=</span><span class="pln"> webdriver</span><span class="pun">.</span><span class="typ">Firefox</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> browser</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'https://nostarch.com'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> htmlElem </span><span class="pun">=</span><span class="pln"> browser</span><span class="pun">.</span><span class="pln">find_element_by_tag_name</span><span class="pun">(</span><span class="str">'html'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> htmlElem</span><span class="pun">.</span><span class="pln">send_keys</span><span class="pun">(</span><span class="typ">Keys</span><span class="pun">.</span><span class="pln">END</span><span class="pun">)</span><span class="pln">     </span><span class="com"># scrolls to bottom</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> htmlElem</span><span class="pun">.</span><span class="pln">send_keys</span><span class="pun">(</span><span class="typ">Keys</span><span class="pun">.</span><span class="pln">HOME</span><span class="pun">)</span><span class="pln">    </span><span class="com"># scrolls to top</span></pre>

<p>
	العنصر <code>&lt;html&gt;</code> موجود في كل ملفات HTML، ويكون كامل محتوى مستند HTML داخله؛ وتحديد هذا العنصر مفيد لو أردنا إرسال المفاتيح إلى صفحة الويب عمومًا، وهذا بدوره مفيد إذا كانت الصفحة تحمِّل محتوى جديد عند التمرير إلى أسفل الصفحة.
</p>

<h3 id="-13">
	الضغط على أزرار المتصفح
</h3>

<p>
	يمكن أن تحاكي الوحدة <code>selenium</code> الضغط على أزرار المتصفح المختلفة:
</p>

<ul>
	<li>
		التابع <code>browser.back()‎</code> يضغط على زر الرجوع
	</li>
	<li>
		التابع <code>browser.forward()‎</code> يضغط على زر إلى الأمام
	</li>
	<li>
		التابع <code>browser.refresh()‎</code> يضغط على زر التحديث
	</li>
	<li>
		التابع <code>browser.quit()‎</code> يضغط على زر إغلاق النافذة
	</li>
</ul>

<h3 id="selenium-2">
	المزيد من المعلومات حول Selenium
</h3>

<p>
	يمكن للوحدة <code>selenium</code> فعل الكثير مما لم نذكره هنا، فيمكنك أن تعدل محتوى ملفات تعريف الارتباط، وتأخذ لقطة شاشة، وتشغل سكربت <a href="https://academy.hsoub.com/javascript/" rel="">JavaScript</a> مخصص …إلخ. لمزيد من المعلومات حول تلك الخصائص فأنصحك أن تزور <a href="https://selenium-python.readthedocs.org/" rel="external nofollow">التوثيق الرسمي</a>.
</p>

<h2 id="-14">
	الخلاصة
</h2>

<p>
	المهام المملة ليست متعلقة بالملفات المحلية على حاسوبك. إذا كنت قادرًا على تنزيل صفحات الويب برمجيًا فستستطيع أتمتة أي مهمة تردك! تسهل الوحدة <code>requests</code> تنزيل صفحات الويب، وبعد تعلم أساسيات HTML فيمكنك أن تستخدم الوحدة <code>BeautifulSoup</code> لتفسير الصفحات التي تنزلها. لكن إن كانت تريد أتمتة أي مهمة متعلقة بالويب أيًا كانت، فيمكنك التحكم برمجيًا مباشرةً بمتصفح الويب عبر الوحدة <code>selenium</code>، التي تسمح لك بفتح المواقع وملء الاستمارات كما لو كان برنامجك كائنًا بشريًا يتصفح المواقع.
</p>

<h2 id="-16">
	مشاريع تدريبية
</h2>

<p>
	لكي تتدرب، اكتب برامج لتنفيذ المهام الآتية.
</p>

<h3 id="-17">
	إرسال البريد الإلكتروني من سطر الأوامر
</h3>

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

<h3 id="-18">
	منزِّل الصور
</h3>

<p>
	اكتب برنامج يفتح أحد مواقع مشاركة الصور مثل Flickr ويبحث عن تصنيف معين من الصور وينزل جميع نتائج البحث في الصفحة الأولى. يمكنك أن تكتب برنامج يعمل على أي موقع مشاركة صور ولديه خاصية البحث.
</p>

<h3 id="2048">
	لعبة 2048
</h3>

<p>
	لعبة 2048 هي لعبة بسيطة تسمح لك بجمع مربعات بجعلها تنزلق إلى أحد الاتجاهات باستخدام أزرار الأسهم. يمكنك أن تحصل على نتيجة عالية إذا جعلت الانزلاق بهذا الترتيب مرارًا وتكرارًا: الأعلى ثم اليمين ثم الأسفل ثم اليسار. اكتب برنامج بسيط يفتح اللعبة <a href="https://gabrielecirulli.github.io/2048/" rel="external nofollow">gabrielecirulli.github.io</a> وينفذ النمط السابق للعب اللعبة تلقائيًا.
</p>

<h3 id="-19">
	التحقق من الروابط
</h3>

<p>
	اكتب برنامج يأخذ رابط URL من صفحة ويب، ويحاول أن ينزل كل صفحة مرتبطة فيها، ويُعلِّم كل الصفحات التي تعيد 404 وتؤشر عليها أنها روابط مكسورة.
</p>

<p>
	ترجمة -بتصرف- للمقال <a href="https://automatetheboringstuff.com/2e/chapter12/" rel="external nofollow">Web Scraping</a> من كتاب <a href="https://automatetheboringstuff.com/2e/" rel="external nofollow">Automate the Boring Stuff with Python</a>.
</p>

<h2 id="-20">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/python/%D8%AA%D9%86%D9%82%D9%8A%D8%AD-%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-debugging-%D8%B4%D9%8A%D9%81%D8%B1%D8%AA%D9%83-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r2359/" rel="">تنقيح أخطاء Debugging شيفرتك البرمجية باستخدام لغة بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%B9%D9%85%D9%84%D8%A7%D8%A1-%D9%88%D9%8A%D8%A8-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1523/" rel="">برمجة عملاء ويب باستخدام بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D8%A3%D9%87%D9%85-10-%D9%85%D9%83%D8%AA%D8%A8%D8%A7%D8%AA-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%AA%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%B4%D8%A7%D8%B1%D9%8A%D8%B9-%D8%A7%D9%84%D8%B5%D8%BA%D9%8A%D8%B1%D8%A9-r654/" rel="">أهم 10 مكتبات بايثون تستخدم في المشاريع الصغيرة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D9%85%D8%B4%D8%A7%D8%B1%D9%8A%D8%B9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D9%86%D8%A7%D8%B3%D8%A8-%D8%A7%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86-r2185/" rel="">مشاريع بايثون عملية تناسب المبتدئين</a>
	</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>
</ul>
]]></description><guid isPermaLink="false">2366</guid><pubDate>Thu, 18 Jul 2024 15:05:01 +0000</pubDate></item><item><title>&#x62A;&#x646;&#x642;&#x64A;&#x62D; &#x623;&#x62E;&#x637;&#x627;&#x621; Debugging &#x634;&#x64A;&#x641;&#x631;&#x62A;&#x643; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x64A;&#x629; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x644;&#x63A;&#x629; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646;</title><link>https://academy.hsoub.com/programming/python/%D8%AA%D9%86%D9%82%D9%8A%D8%AD-%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-debugging-%D8%B4%D9%8A%D9%81%D8%B1%D8%AA%D9%83-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r2359/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_07/------.png.f15e0f7d690a89844d068da676a5b015.png" /></p>
<p>
	تعرّفتَ في المقالات السابقة على معلومات كافية لكتابة برامج أكثر تعقيدًا، ولكنك ستعثر على أخطاء كثيرة فيها، لذا سنوضّح في هذا المقال بعض الأدوات والتقنيات لإيجاد السبب الجذري للأخطاء في برنامجك لمساعدتك في إصلاح الأخطاء بسرعةٍ أكبر وبجهد أقل.
</p>

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

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

<h2 id="raisingexceptions">
	رفع الاستثناءات Raising Exceptions
</h2>

<p>
	ترفع <a href="https://academy.hsoub.com/programming/python/%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-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1815/" rel="">لغة بايثون Python</a> استثناءً عندما تحاول تنفيذ شيفرة برمجية غير صالحة، حيث تعرّفنا في <a href="https://academy.hsoub.com/programming/python/%D8%A8%D9%86%D9%89-%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2335/" rel="">مقالٍ سابق</a> على كيفية التعامل مع استثناءات بايثون باستخدام تعليمتي <code>try</code> و <code>except</code> حتى يتمكّن برنامجك من التعافي من الاستثناءات المُتوقَّعة. يمكنك أيضًا رفع استثناءاتك الخاصة في شيفرتك البرمجية، حيث يمثّل رفع الاستثناء طريقةً لإيقاف تشغيل الشيفرة البرمجية في هذه الدالة ونقل تنفيذ البرنامج إلى التعليمة <code>except</code>.
</p>

<p>
	تُرفَع الاستثناءات باستخدام التعليمة <code>raise</code> التي تتكون ممّا يلي:
</p>

<ul>
	<li>
		الكلمة المفتاحية <code>raise</code>.
	</li>
	<li>
		استدعاء الدالة <code>Exception()‎</code>.
	</li>
	<li>
		سلسلة نصية تحتوي على رسالة خطأ مفيدة نمرَّرها إلى الدالة <code>Exception()‎</code>.
	</li>
</ul>

<p>
	لندخِل مثلًا ما يلي في الصدفة التفاعلية Interactive Shell:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_17" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">raise</span><span class="pln"> </span><span class="typ">Exception</span><span class="pun">(</span><span class="str">'This is the error message.'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#191&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="kwd">raise</span><span class="pln"> </span><span class="typ">Exception</span><span class="pun">(</span><span class="str">'This is the error message.'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Exception</span><span class="pun">:</span><span class="pln"> </span><span class="typ">This</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> the error message</span><span class="pun">.</span></pre>

<p>
	إن لم تُوجَد تعليمات <code>try</code> و <code>except</code> المغلِّفة للتعليمة <code>except</code> التي ترفع الاستثناء، فسيتعطل البرنامج ويعرض رسالة خطأ الاستثناء ببساطة.
</p>

<p>
	تعرِف الشيفرة البرمجية التي تستدعي الدالة -وليس الدالة نفسها- كيفية التعامل مع الاستثناء، وهذا يعني أنك سترى التعليمة <code>raise</code> ضمن الدالة وتعليمتي <code>try</code> و <code>except</code> في الشيفرة البرمجية التي تستدعي هذه الدالة. افتح تبويبًا جديدًا في محرّرك لإنشاء ملف جديد، وأدخِل مثلًا الشيفرة البرمجية التالية واحفظ البرنامج بالاسم boxPrint.py:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_19" style=""><span class="kwd">def</span><span class="pln"> boxPrint</span><span class="pun">(</span><span class="pln">symbol</span><span class="pun">,</span><span class="pln"> width</span><span class="pun">,</span><span class="pln"> height</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">symbol</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="pun">➊</span><span class="pln"> </span><span class="kwd">raise</span><span class="pln"> </span><span class="typ">Exception</span><span class="pun">(</span><span class="str">'Symbol must be a single character string.'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> width </span><span class="pun">&lt;=</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="kwd">raise</span><span class="pln"> </span><span class="typ">Exception</span><span class="pun">(</span><span class="str">'Width must be greater than 2.'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> height </span><span class="pun">&lt;=</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="kwd">raise</span><span class="pln"> </span><span class="typ">Exception</span><span class="pun">(</span><span class="str">'Height must be greater than 2.'</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">symbol </span><span class="pun">*</span><span class="pln"> width</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="pln">height </span><span class="pun">-</span><span class="pln"> </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">symbol </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="str">' '</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </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="pun">))</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> symbol</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">symbol </span><span class="pun">*</span><span class="pln"> width</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> sym</span><span class="pun">,</span><span class="pln"> w</span><span class="pun">,</span><span class="pln"> h </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">((</span><span class="str">'*'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">),</span><span class="pln"> </span><span class="pun">(</span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">20</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">),</span><span class="pln"> </span><span class="pun">(</span><span class="str">'x'</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">3</span><span class="pun">),</span><span class="pln"> </span><span class="pun">(</span><span class="str">'ZZ'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)):</span><span class="pln">
    </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
        boxPrint</span><span class="pun">(</span><span class="pln">sym</span><span class="pun">,</span><span class="pln"> w</span><span class="pun">,</span><span class="pln"> h</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">Exception</span><span class="pln"> </span><span class="kwd">as</span><span class="pln"> err</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="str">'An exception happened: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">err</span><span class="pun">))</span></pre>

<p>
	اطّلع على <a href="https://autbor.com/boxprint" rel="external nofollow">تنفيذ هذا البرنامج</a>، حيث عرّفنا الدالة <code>boxPrint()‎</code> التي تأخذ محرفًا وعرضًا وارتفاعًا، وتستخدم هذا المحرف لإنشاء صورة صغيرة لمربع له هذا العرض والارتفاع، وتطبع شكل هذا المربع على الشاشة.
</p>

<p>
	لنفترض أننا نريد أن يكون هذا المحرف مفردًا، وأن يكون العرض والارتفاع أكبر من 2، فسنضيف تعليمات <code>if</code> لرفع الاستثناءات عند عدم استيفاء هذه المتطلبات. ستتعامل لاحقًا تعليمات <code>try</code>/<code>except</code> مع الوسطاء غير الصالحة عندما نستدعي الدالة ‎<code>boxPrint()</code>‎ مع وسطاء مختلفة.
</p>

<p>
	يستخدم هذا البرنامج الصيغة <code>except Exception as err</code> للتعليمة <code>except</code> ➍. إذا أُعيد الكائن <code>Exception</code> من الدالة <code>boxPrint()‎</code> ➊ ➋ ➌، فستخزِّنه التعليمة <code>except</code> في متغير بالاسم <code>err</code>، ثم يمكننا تحويل الكائن <code>Exception</code> إلى سلسلة نصية من خلال تمريره إلى الدالة ‎<code>str()</code>‎ لإعطاء رسالة خطأ مألوفة للمستخدم ➎، وسيبدو الخرج كما يلي عند تشغيل البرنامج boxPrint.py:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_21" 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">
OOOOOOOOOOOOOOOOOOOO
O                  O
O                  O
O                  O
OOOOOOOOOOOOOOOOOOOO
</span><span class="typ">An</span><span class="pln"> exception happened</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Width</span><span class="pln"> must be greater than </span><span class="lit">2.</span><span class="pln">
</span><span class="typ">An</span><span class="pln"> exception happened</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Symbol</span><span class="pln"> must be a single character string</span><span class="pun">.</span></pre>

<p>
	يمكنك التعامل مع الأخطاء بأمان أكبر باستخدام تعليمات <code>try</code> و <code>except</code> بدلًا من ترك البرنامج يتعطل بأكمله.
</p>

<h2 id="traceback">
	الحصول على التعقب العكسي Traceback كسلسلة نصية
</h2>

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

<p>
	افتح تبويبًا جديدًا في محرّر Mu لإنشاء ملف جديد، وأدخِل البرنامج التالي واحفظه بالاسم errorExample.py:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_23" style=""><span class="kwd">def</span><span class="pln"> spam</span><span class="pun">():</span><span class="pln">
    beef</span><span class="pun">()</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> beef</span><span class="pun">():</span><span class="pln">
    </span><span class="kwd">raise</span><span class="pln"> </span><span class="typ">Exception</span><span class="pun">(</span><span class="str">'This is the error message.'</span><span class="pun">)</span><span class="pln">

spam</span><span class="pun">()</span></pre>

<p>
	سيبدو الخرج كما يلي عند تشغيل البرنامج errorExample.py:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_25" style=""><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"errorExample.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">7</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    spam</span><span class="pun">()</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"errorExample.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> spam
    beef</span><span class="pun">()</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"errorExample.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> beef
    </span><span class="kwd">raise</span><span class="pln"> </span><span class="typ">Exception</span><span class="pun">(</span><span class="str">'This is the error message.'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Exception</span><span class="pun">:</span><span class="pln"> </span><span class="typ">This</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> the error message</span><span class="pun">.</span></pre>

<p>
	يمكنك أن ترى من التعقّب العكسي السابق أن الخطأ حدث في السطر رقم 5 في الدالة <code>beef()‎</code>، وأتى هذا الاستدعاء للدالة <code>beef()‎</code> من السطر رقم 2 في الدالة <code>spam()‎</code> التي اُستدعيت بدورها في السطر رقم 7. يمكن أن يساعدك مكدس الاستدعاءات في تحديد الاستدعاء الذي أدى إلى الخطأ في البرامج التي يمكن فيها استدعاء <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2336/" rel="">الدوال</a> من أماكن متعددة.
</p>

<p>
	تعرض لغة بايثون التعقّب العكسي عند عدم التعامل مع الاستثناء المرفوع، ولكن يمكنك أيضًا الحصول على التعقب العكسي بوصفه سلسلة نصية من خلال استدعاء الدالة <code>traceback.format_exc()‎</code>، حيث تكون هذه الدالة مفيدة إذا أردتَ الحصول على المعلومات من التعقب العكسي الخاص بالاستثناء ولكنك تريد أيضًا التعليمة <code>except</code> للتعامل مع الاستثناء بأمان. يجب استيراد الوحدة <code>traceback</code> الخاصة بلغة بايثون قبل استدعاء هذه الدالة.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_27" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> traceback
</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">Exception</span><span class="pun">(</span><span class="str">'This is the error message.'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">except</span><span class="pun">:</span><span class="pln">
</span><span class="pun">...</span><span class="pln">          errorFile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'errorInfo.txt'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'w'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">...</span><span class="pln">          errorFile</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">traceback</span><span class="pun">.</span><span class="pln">format_exc</span><span class="pun">())</span><span class="pln">
</span><span class="pun">...</span><span class="pln">          errorFile</span><span class="pun">.</span><span class="pln">close</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="str">'The traceback info was written to errorInfo.txt.'</span><span class="pun">)</span><span class="pln">


</span><span class="lit">111</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> traceback info was written to errorInfo</span><span class="pun">.</span><span class="pln">txt</span><span class="pun">.</span></pre>

<p>
	تُعَد القيمة <code>111</code> هي القيمة التي يعيدها التابع <code>write()‎</code>، حيث كُتِبت المحارف 111 في الملف، وكُتِب نص التعقّب العكسي في الملف errorInfo.txt:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_29" style=""><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#28&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Exception</span><span class="pun">:</span><span class="pln"> </span><span class="typ">This</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> the error message</span><span class="pun">.</span></pre>

<p>
	سنتعلّم لاحقًا كيفية استخدام الوحدة <code>logging</code> التي تُعَد أكثر فعالية من مجرد كتابة معلومات الخطأ في ملفات نصية.
</p>

<h2 id="assertions">
	التأكيدات Assertions
</h2>

<p>
	يُعَد التأكيد Assertion فحص سلامةٍ للتأكد من أن شيفرتك البرمجية لا تفعل شيئًا خاطئًا، حيث يمكن إجراء عمليات التحقق من السلامة من خلال استخدام التعليمة <code>assert</code>، وإذا فشل التحقق من السلامة، فسيُرفَع الاستثناء <code>AssertionError</code>. تتكون التعليمة <code>assert</code> مما يلي في الشيفرة البرمجية:
</p>

<ul>
	<li>
		الكلمة المفتاحية <code>assert</code>.
	</li>
	<li>
		شرط (أيّ تعبير يمكن تقييمه بالقيمة <code>True</code> أو <code>False</code>).
	</li>
	<li>
		فاصلة.
	</li>
	<li>
		سلسلة نصية تُعرَض عندما تكون قيمة الشرط <code>False</code>.
	</li>
</ul>

<p>
	تمثّل التعليمة <code>assert</code> التأكيد على أن الشرط صحيح، وإذا لم يكن الأمر كذلك، فلا بد من وجود خطأٍ في مكانٍ ما، لذا يجب إيقاف البرنامج مباشرةً. أدخِل مثلًا ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_31" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> ages </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">26</span><span class="pun">,</span><span class="pln"> </span><span class="lit">57</span><span class="pun">,</span><span class="pln"> </span><span class="lit">92</span><span class="pun">,</span><span class="pln"> </span><span class="lit">54</span><span class="pun">,</span><span class="pln"> </span><span class="lit">22</span><span class="pun">,</span><span class="pln"> </span><span class="lit">15</span><span class="pun">,</span><span class="pln"> </span><span class="lit">17</span><span class="pun">,</span><span class="pln"> </span><span class="lit">80</span><span class="pun">,</span><span class="pln"> </span><span class="lit">47</span><span class="pun">,</span><span class="pln"> </span><span class="lit">73</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> ages</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> ages
</span><span class="pun">[</span><span class="lit">15</span><span class="pun">,</span><span class="pln"> </span><span class="lit">17</span><span class="pun">,</span><span class="pln"> </span><span class="lit">22</span><span class="pun">,</span><span class="pln"> </span><span class="lit">26</span><span class="pun">,</span><span class="pln"> </span><span class="lit">47</span><span class="pun">,</span><span class="pln"> </span><span class="lit">54</span><span class="pun">,</span><span class="pln"> </span><span class="lit">57</span><span class="pun">,</span><span class="pln"> </span><span class="lit">73</span><span class="pun">,</span><span class="pln"> </span><span class="lit">80</span><span class="pun">,</span><span class="pln"> </span><span class="lit">92</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">assert</span><span class="pln">
ages</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;=</span><span class="pln"> ages</span><span class="pun">[-</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="com"># تأكيد أن العمر الأول &lt;= العمر الأخير</span></pre>

<p>
	تؤكّد التعليمة <code>assert</code> في المثال السابق على أن العنصر الأول في القائمة <code>ages</code> يجب أن يكون أصغر من العنصر الأخير أو يساويه، ويمثّل ذلك التحقق من السلامة، حيث إذا كانت الشيفرة البرمجية الموجودة في التابع ‎<code>sort()</code>‎ خالية من الأخطاء وأدت عملها، فسيكون التأكيد صحيحًا.
</p>

<p>
	يُقيَّم التعبير <code>ages[0] &lt;= ages[-1]‎</code> على أنه <code>True</code>، وبالتالي لن تفعل التعليمة <code>assert</code> شيئًا، ولكن لنتظاهر بوجود خطأ في شيفرتنا البرمجية، ولنفترض أننا استدعينا عن طريق الخطأ تابعَ القائمة <code>reverse()‎</code> بدلًا من تابع القائمة <code>sort()‎</code>، حيث سترفع التعليمة <code>assert</code> خطأ <code>AssertionError</code> مثلًا عندما ندخِل ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_33" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> ages </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">26</span><span class="pun">,</span><span class="pln"> </span><span class="lit">57</span><span class="pun">,</span><span class="pln"> </span><span class="lit">92</span><span class="pun">,</span><span class="pln"> </span><span class="lit">54</span><span class="pun">,</span><span class="pln"> </span><span class="lit">22</span><span class="pun">,</span><span class="pln"> </span><span class="lit">15</span><span class="pun">,</span><span class="pln"> </span><span class="lit">17</span><span class="pun">,</span><span class="pln"> </span><span class="lit">80</span><span class="pun">,</span><span class="pln"> </span><span class="lit">47</span><span class="pun">,</span><span class="pln"> </span><span class="lit">73</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> ages</span><span class="pun">.</span><span class="pln">reverse</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> ages
</span><span class="pun">[</span><span class="lit">73</span><span class="pun">,</span><span class="pln"> </span><span class="lit">47</span><span class="pun">,</span><span class="pln"> </span><span class="lit">80</span><span class="pun">,</span><span class="pln"> </span><span class="lit">17</span><span class="pun">,</span><span class="pln"> </span><span class="lit">15</span><span class="pun">,</span><span class="pln"> </span><span class="lit">22</span><span class="pun">,</span><span class="pln"> </span><span class="lit">54</span><span class="pun">,</span><span class="pln"> </span><span class="lit">92</span><span class="pun">,</span><span class="pln"> </span><span class="lit">57</span><span class="pun">,</span><span class="pln"> </span><span class="lit">26</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">assert</span><span class="pln"> ages</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;=</span><span class="pln"> ages</span><span class="pun">[-</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="com"># تأكيد أن العمر الأول &lt;= العمر الأخير</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;stdin&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">AssertionError</span></pre>

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

<p>
	تُعَد التأكيدات مُخصَّصة لأخطاء المبرمج وليست خاصة بأخطاء المستخدم، إذ يجب أن تفشل التأكيدات فقط عندما يكون البرنامج قيد التطوير، ويجب ألّا يرى المستخدم أبدًا خطأ تأكيد في البرنامج النهائي، لذا يجب أن ترفع استثناءً بدلًا من اكتشافه باستخدام التعليمة <code>assert</code> بالنسبة للأخطاء التي يمكن أن يتعرض لها برنامجك كجزءٍ عادي من عمله مثل عدم العثور على ملف أو إدخال المستخدم بيانات غير صالحة، ويجب ألّا تستخدم تعليمات <code>assert</code> بدلًا من رفع الاستثناءات، لأنه يمكن للمستخدمين اختيار إيقاف التأكيدات. إذا شغّلتَ سكربت بايثون باستخدام الأمر <code>python -O myscript.py</code> بدلًا من الأمر <code>python myscript.py</code>، فستتخطّى شيفرة <a href="https://wiki.hsoub.com/Python" rel="external">بايثون</a> تعليمات <code>assert</code>، وقد يعطّل المستخدمون التأكيدات عندما يطورون برنامجًا ويحتاجون إلى تشغيله في بيئة الإنتاج التي تتطلب أداءً أعلى، بالرغم من أنهم في كثير من الحالات سيتركون التأكيدات مفعّلة حتى في ذلك الوقت.
</p>

<p>
	لا تُعَد التأكيدات بديلًا عن الاختبار الشامل، فمثلًا إذا ضبطنا القائمة <code>ages</code> في المثال السابق على القيمة <code>[10, 3, 2, 1, 20]</code>، فلن تلاحظ تعليمة التأكيد <code>assert ages[0] &lt;= ages[-1]‎</code> أن القائمة غير مرتبة، لأنها ترى أن العمر الأول أصغر من أو يساوي العمر الأخير، وهو الشيء الوحيد الذي تتحقق منه تعليمة التأكيد.
</p>

<h3 id="">
	استخدام التأكيد في برنامج لمحاكاة إشارات المرور
</h3>

<p>
	لنفترض أنك تنشئ برنامجًا لمحاكاة إشارات المرور، حيث يكون هيكل البيانات الذي يمثّل إشارات التوقف عند التقاطع هو قاموس له المفاتيح <code>'ns'</code> و <code>'ew'</code> لإشارات التوقف التي تمثّل جهة الشمال-الجنوب وجهة الشرق-الغرب على التوالي. ستكون القيم الموجودة في هذه المفاتيح إحدى السلاسل النصية <code>'green'</code> أو <code>'yellow'</code> أو <code>'red'</code>، حيث ستبدو الشيفرة البرمجية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_35" style=""><span class="pln">market_2nd </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'ns'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'green'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'ew'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'red'</span><span class="pun">}</span><span class="pln">
mission_16th </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'ns'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'red'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'ew'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'green'</span><span class="pun">}</span></pre>

<p>
	يمثّل المتغيران السابقان تقاطعات شارع السوق Market Street والشارع الثاني 2nd Street، وشارع ميشن Mission Street والشارع السادس عشر 16th Street. نبدأ المشروع من خلال كتابة الدالة ‎<code>switchLights()</code>‎ التي تأخذ قاموسًا يمثّل التقاطع بوصفه وسيطًا وتبّدل بين الأضواء.
</p>

<p>
	نعتقد في البداية أن الدالة ‎<code>switchLights()</code>‎ يجب أن تحوّل ببساطة كل ضوء إلى اللون التالي في السلسلة، حيث يجب أن تتغيّر جميع القيم <code>'green'</code> إلى القيمة <code>'yellow'</code>، ويجب أن تتغير قيم <code>'yellow'</code> إلى القيم <code>'red'</code>، ويجب أن تتغير القيم <code>'red'</code> إلى القيم <code>'green'</code>، إذ قد تبدو الشيفرة البرمجية لتطبيق هذه الفكرة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_37" style=""><span class="kwd">def</span><span class="pln"> switchLights</span><span class="pun">(</span><span class="pln">stoplight</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> key </span><span class="kwd">in</span><span class="pln"> stoplight</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">():</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> stoplight</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">'green'</span><span class="pun">:</span><span class="pln">
            stoplight</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'yellow'</span><span class="pln">
        </span><span class="kwd">elif</span><span class="pln"> stoplight</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">'yellow'</span><span class="pun">:</span><span class="pln">
            stoplight</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'red'</span><span class="pln">
        </span><span class="kwd">elif</span><span class="pln"> stoplight</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">'red'</span><span class="pun">:</span><span class="pln">
            stoplight</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'green'</span><span class="pln">

switchLights</span><span class="pun">(</span><span class="pln">market_2nd</span><span class="pun">)</span></pre>

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

<p>
	إذا أضفتَ‎ تأكيدًا أثناء كتابة الدالة <code>switchLights()‎</code> للتحقّق من أن أحد الأضواء يكون دائمًا باللون الأحمر على الأقل، فيمكن تضمين ما يلي في نهاية الدالة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_39" style=""><span class="kwd">assert</span><span class="pln"> </span><span class="str">'red'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> stoplight</span><span class="pun">.</span><span class="pln">values</span><span class="pun">(),</span><span class="pln"> </span><span class="str">'Neither light is red! '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">stoplight</span><span class="pun">)</span></pre>

<p>
	سيتعطّل برنامجك مع ظهور رسالة الخطأ التالية باستخدام التأكيد السابق:
</p>

<pre class="ipsCode">   Traceback (most recent call last):
     File "carSim.py", line 14, in &lt;module&gt;
       switchLights(market_2nd)
     File "carSim.py", line 13, in switchLights
       assert 'red' in stoplight.values(), 'Neither light is red! ' +
   str(stoplight)
➊ AssertionError: Neither light is red! {'ns': 'yellow', 'ew': 'green'}
</pre>

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

<h2 id="logging">
	التسجيل Logging
</h2>

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

<h3 id="logging-1">
	استخدام الوحدة logging
</h3>

<p>
	يمكن تفعيل الوحدة <code>logging</code> لعرض رسائل السجل على شاشتك أثناء تشغيل البرنامج من خلال نسخ ما يلي إلى بداية برنامجك، ولكن ضمّن السطر Shebang الذي هو <code>‎#! python</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_41" style=""><span class="kwd">import</span><span class="pln"> logging
logging</span><span class="pun">.</span><span class="pln">basicConfig</span><span class="pun">(</span><span class="pln">level</span><span class="pun">=</span><span class="pln">logging</span><span class="pun">.</span><span class="pln">DEBUG</span><span class="pun">,</span><span class="pln"> format</span><span class="pun">=</span><span class="str">' %(asctime)s -  %(levelname)
s -  %(message)s'</span><span class="pun">)</span></pre>

<p>
	لا داعي للقلق كثيرًا بشأن كيفية عمل السطر السابق، ولكنه ينشئ الكائن <code>LogRecord</code> الذي يحتوي على معلومات حول حدثٍ ما عندما تسجّل بايثون هذا الحدث. تتيح لك الدالة <code>basicConfig()‎</code> الخاصة بالوحدة <code>logging</code> تحديدَ التفاصيل المتعلقة بكائن <code>LogRecord</code> الذي تريد رؤيته وكيفية عرض هذه التفاصيل.
</p>

<p>
	لنفترض أنك كتبتَ دالةً لحساب عاملي Factorial عددٍ ما، حيث يكون عاملي العدد 4 في الرياضيات هو 1‎ × 2 × 3 × 4 أو القيمة 24 وعاملي العدد 7 هو 1‎ × 2 × 3 × 4 × 5 × 6 × 7 أو القيمة 5040. افتح تبويبًا جديدًا في محرّرك لإنشاء ملف جديد وأدخِل الشيفرة البرمجية التالية التي تحتوي على خطأ، ولكنك ستدخِل أيضًا عددًا من رسائل السجل لمساعدة نفسك في اكتشاف الخطأ الذي يحدث، واحفظ البرنامج بالاسم factorialLog.py:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_43" style=""><span class="kwd">import</span><span class="pln"> logging
logging</span><span class="pun">.</span><span class="pln">basicConfig</span><span class="pun">(</span><span class="pln">level</span><span class="pun">=</span><span class="pln">logging</span><span class="pun">.</span><span class="pln">DEBUG</span><span class="pun">,</span><span class="pln"> format</span><span class="pun">=</span><span class="str">'%(asctime)s -  %(levelname)s
-  %(message)s'</span><span class="pun">)</span><span class="pln">
logging</span><span class="pun">.</span><span class="pln">debug</span><span class="pun">(</span><span class="str">'Start of program'</span><span class="pun">)</span><span class="pln">

</span><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">
    logging</span><span class="pun">.</span><span class="pln">debug</span><span class="pun">(</span><span class="str">'Start of factorial(%s%%)'</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">
    total </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</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="pln">n </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">):</span><span class="pln">
        total </span><span class="pun">*=</span><span class="pln"> i
        logging</span><span class="pun">.</span><span class="pln">debug</span><span class="pun">(</span><span class="str">'i is '</span><span class="pln"> </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="str">', total is '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">total</span><span class="pun">))</span><span class="pln">
    logging</span><span class="pun">.</span><span class="pln">debug</span><span class="pun">(</span><span class="str">'End of factorial(%s%%)'</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">
    </span><span class="kwd">return</span><span class="pln"> total

</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">factorial</span><span class="pun">(</span><span class="lit">5</span><span class="pun">))</span><span class="pln">
logging</span><span class="pun">.</span><span class="pln">debug</span><span class="pun">(</span><span class="str">'End of program'</span><span class="pun">)</span></pre>

<p>
	نستخدم الدالة <code>logging.debug()‎</code> عندما نريد طباعة معلومات السجل، وتستدعي الدالةُ <code>debug()‎</code> الدالةَ <code>basicConfig()‎</code> وستطبع سطرًا من المعلومات، حيث ستكون هذه المعلومات بالتنسيق الذي حددناه في الدالة <code>basicConfig()‎</code> وستتضمّن الرسائل التي مرّرناها إلى الدالة <code>debug()‎</code>. يُعَد استدعاء الدالة <code>print(factorial(5))‎</code> جزءًا من البرنامج الأصلي، لذا ستُعرَض النتيجة حتى لو تعطّلت رسائل التسجيل.
</p>

<p>
	يبدو خرج هذا البرنامج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_45" style=""><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">16</span><span class="pun">:</span><span class="lit">20</span><span class="pun">:</span><span class="lit">12</span><span class="pun">,</span><span class="lit">664</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Start</span><span class="pln"> of program
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">16</span><span class="pun">:</span><span class="lit">20</span><span class="pun">:</span><span class="lit">12</span><span class="pun">,</span><span class="lit">664</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Start</span><span class="pln"> of factorial</span><span class="pun">(</span><span class="lit">5</span><span class="pun">)</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">16</span><span class="pun">:</span><span class="lit">20</span><span class="pun">:</span><span class="lit">12</span><span class="pun">,</span><span class="lit">665</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> i </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> total </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">16</span><span class="pun">:</span><span class="lit">20</span><span class="pun">:</span><span class="lit">12</span><span class="pun">,</span><span class="lit">668</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> i </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> total </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">16</span><span class="pun">:</span><span class="lit">20</span><span class="pun">:</span><span class="lit">12</span><span class="pun">,</span><span class="lit">670</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> i </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> total </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">16</span><span class="pun">:</span><span class="lit">20</span><span class="pun">:</span><span class="lit">12</span><span class="pun">,</span><span class="lit">673</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> i </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> total </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">16</span><span class="pun">:</span><span class="lit">20</span><span class="pun">:</span><span class="lit">12</span><span class="pun">,</span><span class="lit">675</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> i </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> total </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">16</span><span class="pun">:</span><span class="lit">20</span><span class="pun">:</span><span class="lit">12</span><span class="pun">,</span><span class="lit">678</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> i </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> total </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">16</span><span class="pun">:</span><span class="lit">20</span><span class="pun">:</span><span class="lit">12</span><span class="pun">,</span><span class="lit">680</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> </span><span class="typ">End</span><span class="pln"> of factorial</span><span class="pun">(</span><span class="lit">5</span><span class="pun">)</span><span class="pln">
</span><span class="lit">0</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">16</span><span class="pun">:</span><span class="lit">20</span><span class="pun">:</span><span class="lit">12</span><span class="pun">,</span><span class="lit">684</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> </span><span class="typ">End</span><span class="pln"> of program</span></pre>

<p>
	تعيد الدالة <code>factorial()‎</code> القيمة 0 بوصفها ناتج عاملي العدد 5، وهذا ليس صحيحًا، حيث يجب أن تضرب <a href="https://wiki.hsoub.com/Python#for" rel="external">حلقة for</a> القيمة الموجودة في المتغير <code>total</code> بالأعداد من 1 إلى 5، ولكن توضّح رسائل السجل التي تعرضها الدالة <code>logging.debug()‎</code> أن المتغير <code>i</code> يبدأ من القيمة 0 بدلًا من القيمة 1، وبالتالي تكون قيمة بقية التكرارات خاطئة للمتغير <code>total</code> أيضًا، لأن ضرب الصفر بأيّ شيء يساوي صفرًا. توفّر رسائل التسجيل سلسلةً من مسارات التنقل التي يمكن أن تساعدك في معرفة متى بدأت الأمور تسوء.
</p>

<p>
	غيّر السطر <code>for i in range(n + 1):‎</code> إلى <code>for i in range(1, n + 1):‎</code>، وشغّل البرنامج مرة أخرى، وسيبدو الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_47" style=""><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">17</span><span class="pun">:</span><span class="lit">13</span><span class="pun">:</span><span class="lit">40</span><span class="pun">,</span><span class="lit">650</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Start</span><span class="pln"> of program
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">17</span><span class="pun">:</span><span class="lit">13</span><span class="pun">:</span><span class="lit">40</span><span class="pun">,</span><span class="lit">651</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Start</span><span class="pln"> of factorial</span><span class="pun">(</span><span class="lit">5</span><span class="pun">)</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">17</span><span class="pun">:</span><span class="lit">13</span><span class="pun">:</span><span class="lit">40</span><span class="pun">,</span><span class="lit">651</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> i </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> total </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">17</span><span class="pun">:</span><span class="lit">13</span><span class="pun">:</span><span class="lit">40</span><span class="pun">,</span><span class="lit">654</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> i </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> total </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">17</span><span class="pun">:</span><span class="lit">13</span><span class="pun">:</span><span class="lit">40</span><span class="pun">,</span><span class="lit">656</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> i </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> total </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">6</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">17</span><span class="pun">:</span><span class="lit">13</span><span class="pun">:</span><span class="lit">40</span><span class="pun">,</span><span class="lit">659</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> i </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> total </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">24</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">17</span><span class="pun">:</span><span class="lit">13</span><span class="pun">:</span><span class="lit">40</span><span class="pun">,</span><span class="lit">661</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> i </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> total </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">120</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">17</span><span class="pun">:</span><span class="lit">13</span><span class="pun">:</span><span class="lit">40</span><span class="pun">,</span><span class="lit">661</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> </span><span class="typ">End</span><span class="pln"> of factorial</span><span class="pun">(</span><span class="lit">5</span><span class="pun">)</span><span class="pln">
</span><span class="lit">120</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">17</span><span class="pun">:</span><span class="lit">13</span><span class="pun">:</span><span class="lit">40</span><span class="pun">,</span><span class="lit">666</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> </span><span class="typ">End</span><span class="pln"> of program</span></pre>

<p>
	يؤدي استدعاء الدالة <code>factorial(5)‎</code> إلى إعادة القيمة 120 الصحيحة، وتظهِر رسائل السجل ما يحدث ضمن الحلقة، مما يقودك إلى الخطأ مباشرةً. يمكنك أن ترى أن استدعاءات الدالة <code>logging.debug()‎</code> لا تطبع السلاسل النصية المُمرَّرة إليها فقط، بل تطبع أيضًا العلامة الزمنية Timestamp والكلمة DEBUG.
</p>

<h3 id="print">
	لا تنقح الأخطاء باستخدام الدالة print()‎
</h3>

<p>
	تُعَد كتابة التعليمتين <code>import logging</code> و <code>logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')‎</code> أمرًا صعبًا بعض الشيء، لذا سترغب في استخدام استدعاءات الدالة ‎<code>print()</code>‎ بدلًا من ذلك، ولكن لا تنخدع بسهولة استخدام هذه الدالة، لأنك ستقضي كثيرًا من الوقت في إزالة استدعاءات الدالة ‎<code>print()</code>‎ من شيفرتك البرمجية لجميع رسائل السجل بعد الانتهاء من تنقيح الأخطاء، وقد تزيل أيضًا عن طريق الخطأ بعض استدعاءات الدالة ‎<code>print()</code>‎ المُستخدَمة للرسائل التي ليس لها علاقة بالسجل. يمكنك ملء برنامجك بالعدد الذي تريده من رسائل السجل، ويمكنك دائمًا تعطيلها لاحقًا من خلال إضافة استدعاء واحد للدالة <code>logging.disable(logging.CRITICAL)‎</code>، حيث تسهّل الوحدة <code>logging</code> التبديل بين إظهار وإخفاء رسائل السجل على عكس الدالة ‎<code>print()</code>‎.
</p>

<p>
	تُعَد رسائل السجل خاصةً بالمبرمج وليست خاصة بالمستخدم، إذ لن يهتم المستخدم بمحتويات بعض قيم القاموس التي تحتاج إلى رؤيتها للمساعدة في تنقيح الأخطاء، لذا استخدم رسالة سجل لذلك، ولكن يجب أن تستخدم استدعاء الدالة ‎<code>print()</code>‎ بالنسبة للرسائل التي يرغب المستخدم في رؤيتها مثل "عدم العثور على ملف File not found" أو "قيمة إدخال غير صالحة لذا أدخِل قيمة عددية من فضلك Invalid input, please enter a number"، فلن ترغب في حرمان المستخدم من المعلومات المفيدة له بعد تعطيل رسائل السجل.
</p>

<h3 id="-1">
	مستويات التسجيل
</h3>

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

<table>
	<thead>
		<tr>
			<th>
				مستوى التسجيل
			</th>
			<th>
				دالة التسجيل
			</th>
			<th>
				وصفها
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				المستوى DEBUG
			</td>
			<td>
				الدالة <code>logging.debug()‎</code>
			</td>
			<td>
				المستوى الأدنى، ويُستخدَم للتفاصيل الصغيرة، حيث تهتم بهذه الرسائل عند تشخيص المشاكل فقط.
			</td>
		</tr>
		<tr>
			<td>
				المستوى INFO
			</td>
			<td>
				الدالة <code>logging.info()‎</code>
			</td>
			<td>
				يُستخدَم لتسجيل معلومات عن الأحداث العامة في برنامجك أو للتأكد من أن الأمور تسير جيدًا في البرنامج.
			</td>
		</tr>
		<tr>
			<td>
				المستوى WARNING
			</td>
			<td>
				الدالة <code>logging.warning()‎</code>
			</td>
			<td>
				يُستخدم للإشارة إلى مشكلة محتملة لا تمنع البرنامج من العمل ولكنها قد تفعل ذلك مستقبلًا.
			</td>
		</tr>
		<tr>
			<td>
				المستوى ERROR
			</td>
			<td>
				الدالة <code>logging.error()‎</code>
			</td>
			<td>
				يُستخدم لتسجيل خطأٍ تسبّب في فشل البرنامج بعمل شيءٍ ما.
			</td>
		</tr>
		<tr>
			<td>
				المستوى CRITICAL
			</td>
			<td>
				الدالة <code>logging.critical()‎</code>
			</td>
			<td>
				المستوى الأعلى، ويُستخدَم للإشارة إلى خطأ كبير تسبّب أو أنه على وشك التسبّب في توقف البرنامج عن العمل بالكامل.
			</td>
		</tr>
	</tbody>
</table>

<p>
	تُمرَّر رسالة التسجيل بوصفها سلسلة نصية إلى هذه الدوال. تُعَد مستويات التسجيل مجرد اقتراحات، فالأمر متروك لك لتحديد الفئة التي تندرج ضمنها رسالة السجل الخاصة بك. لندخِل الآن ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_49" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> logging
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> logging</span><span class="pun">.</span><span class="pln">basicConfig</span><span class="pun">(</span><span class="pln">level</span><span class="pun">=</span><span class="pln">logging</span><span class="pun">.</span><span class="pln">DEBUG</span><span class="pun">,</span><span class="pln"> format</span><span class="pun">=</span><span class="str">' %(asctime)s -
%(levelname)s -  %(message)s'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> logging</span><span class="pun">.</span><span class="pln">debug</span><span class="pun">(</span><span class="str">'Some debugging details.'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">18</span><span class="pln"> </span><span class="lit">19</span><span class="pun">:</span><span class="lit">04</span><span class="pun">:</span><span class="lit">26</span><span class="pun">,</span><span class="lit">901</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> DEBUG </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Some</span><span class="pln"> debugging details</span><span class="pun">.</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> logging</span><span class="pun">.</span><span class="pln">info</span><span class="pun">(</span><span class="str">'The logging module is working.'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">18</span><span class="pln"> </span><span class="lit">19</span><span class="pun">:</span><span class="lit">04</span><span class="pun">:</span><span class="lit">35</span><span class="pun">,</span><span class="lit">569</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> INFO </span><span class="pun">-</span><span class="pln"> </span><span class="typ">The</span><span class="pln"> logging module </span><span class="kwd">is</span><span class="pln"> working</span><span class="pun">.</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> logging</span><span class="pun">.</span><span class="pln">warning</span><span class="pun">(</span><span class="str">'An error message is about to be logged.'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">18</span><span class="pln"> </span><span class="lit">19</span><span class="pun">:</span><span class="lit">04</span><span class="pun">:</span><span class="lit">56</span><span class="pun">,</span><span class="lit">843</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> WARNING </span><span class="pun">-</span><span class="pln"> </span><span class="typ">An</span><span class="pln"> error message </span><span class="kwd">is</span><span class="pln"> about to be logged</span><span class="pun">.</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> logging</span><span class="pun">.</span><span class="pln">error</span><span class="pun">(</span><span class="str">'An error has occurred.'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">18</span><span class="pln"> </span><span class="lit">19</span><span class="pun">:</span><span class="lit">05</span><span class="pun">:</span><span class="lit">07</span><span class="pun">,</span><span class="lit">737</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> ERROR </span><span class="pun">-</span><span class="pln"> </span><span class="typ">An</span><span class="pln"> error has occurred</span><span class="pun">.</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> logging</span><span class="pun">.</span><span class="pln">critical</span><span class="pun">(</span><span class="str">'The program is unable to recover!'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">18</span><span class="pln"> </span><span class="lit">19</span><span class="pun">:</span><span class="lit">05</span><span class="pun">:</span><span class="lit">45</span><span class="pun">,</span><span class="lit">794</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> CRITICAL </span><span class="pun">-</span><span class="pln"> </span><span class="typ">The</span><span class="pln"> program </span><span class="kwd">is</span><span class="pln"> unable to recover</span><span class="pun">!</span></pre>

<p>
	تتمثّل فائدة مستويات التسجيل في أنه يمكنك تغيير أولوية رسالة التسجيل التي تريد رؤيتها، حيث سيؤدي تمرير المستوى <code>logging.DEBUG</code> إلى وسيط الكلمة المفتاحية Keyword Argument الذي هو <code>level</code> الخاص بالدالة <code>basicConfig()‎</code> إلى إظهار الرسائل من جميع مستويات التسجيل، حيث يُعَد المستوى DEBUG هو المستوى الأدنى. قد تكون مهتمًا بالأخطاء فقط بعد تطوير برنامجك، وبالتالي يمكنك ضبط الوسيط <code>level</code> الخاص بالدالة <code>basicConfig()‎</code> على المستوى <code>logging.ERROR</code> في هذه الحالة، إذ سيعرض هذا المستوى رسائل المستوى ERROR ورسائل المستوى CRITICAL فقط ويتخطى رسائل المستويات DEBUG و INFO و WARNING.
</p>

<h3 id="-2">
	تعطيل التسجيل
</h3>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_51" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> logging
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> logging</span><span class="pun">.</span><span class="pln">basicConfig</span><span class="pun">(</span><span class="pln">level</span><span class="pun">=</span><span class="pln">logging</span><span class="pun">.</span><span class="pln">INFO</span><span class="pun">,</span><span class="pln"> format</span><span class="pun">=</span><span class="str">' %(asctime)s -
%(levelname)s -  %(message)s'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> logging</span><span class="pun">.</span><span class="pln">critical</span><span class="pun">(</span><span class="str">'Critical error! Critical error!'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">2024</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">22</span><span class="pln"> </span><span class="lit">11</span><span class="pun">:</span><span class="lit">10</span><span class="pun">:</span><span class="lit">48</span><span class="pun">,</span><span class="lit">054</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> CRITICAL </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Critical</span><span class="pln"> error</span><span class="pun">!</span><span class="pln"> </span><span class="typ">Critical</span><span class="pln"> error</span><span class="pun">!</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> logging</span><span class="pun">.</span><span class="pln">disable</span><span class="pun">(</span><span class="pln">logging</span><span class="pun">.</span><span class="pln">CRITICAL</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> logging</span><span class="pun">.</span><span class="pln">critical</span><span class="pun">(</span><span class="str">'Critical error! Critical error!'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> logging</span><span class="pun">.</span><span class="pln">error</span><span class="pun">(</span><span class="str">'Error! Error!'</span><span class="pun">)</span></pre>

<p>
	ستعطّل الدالة ‎<code>logging.disable()</code>‎ جميع الرسائل بعدها، لذا يُحتمَل أنك تريد إضافتها بالقرب من سطر الاستيراد <code>import logging</code> في برنامجك، وبالتالي يمكنك بسهولة العثور عليه لتعليق هذا الاستدعاء أو إلغاء تعليقه لتفعيل رسائل التسجيل أو تعطيلها حسب الحاجة.
</p>

<h3 id="-3">
	التسجيل في ملف
</h3>

<p>
	يمكنك كتابة رسائل السجل في ملف نصي بدلًا من عرضها على الشاشة، حيث تأخذ الدالة <code>logging.basicConfig()‎</code> وسيط الكلمة المفتاحية <code>filename</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_53" style=""><span class="kwd">import</span><span class="pln"> logging
logging</span><span class="pun">.</span><span class="pln">basicConfig</span><span class="pun">(</span><span class="pln">filename</span><span class="pun">=</span><span class="str">'myProgramLog.txt'</span><span class="pun">,</span><span class="pln"> level</span><span class="pun">=</span><span class="pln">logging</span><span class="pun">.</span><span class="pln">DEBUG</span><span class="pun">,</span><span class="pln"> format</span><span class="pun">=</span><span class="str">'
%(asctime)s -  %(levelname)s -  %(message)s'</span><span class="pun">)</span></pre>

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

<h2 id="mu">
	منقح أخطاء المحرر Mu
</h2>

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

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="152719" href="https://academy.hsoub.com/uploads/monthly_2024_07/01_000049.jpg.cf12e73dd25e9201c2338979cd90e773.jpg" rel=""><img alt="01 000049" class="ipsImage ipsImage_thumbnailed" data-fileid="152719" data-unique="pt5s5l34f" src="https://academy.hsoub.com/uploads/monthly_2024_07/01_000049.jpg.cf12e73dd25e9201c2338979cd90e773.jpg"> </a>
</p>

<p style="text-align: center;">
	تشغيل المحرّر Mu لبرنامجٍ ما مع منقّح الأخطاء
</p>

<p>
	يضيف وضع تنقيح الأخطاء أيضًا أزرارًا جديدة إلى أعلى المحرّر وهي: زر المتابعة "Continue" وزر "Step Over" وزر "Step In" وزر "Step Out"، ويوجد زر التوقف "Stop" المعتاد أيضًا.
</p>

<h3 id="continue">
	زر المتابعة Continue
</h3>

<p>
	يؤدي النقر على زر المتابعة "Continue" إلى تنفيذ البرنامج بطريقة طبيعية حتى ينتهي البرنامج أو يصل إلى نقطة توقف Breakpoint (سنوضح نقاط التوقف لاحقًا في هذا المقال). إذا انتهيتَ من تنقيح الأخطاء وأردتَ أن يتابع البرنامج عمله بطريقة طبيعية، فانقر على زر المتابعة "Continue".
</p>

<h3 id="stepin">
	زر Step In
</h3>

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

<h3 id="stepover">
	زر Step Over
</h3>

<p>
	يؤدي النقر على زر "Step Over" إلى تنفيذ السطر التالي من الشيفرة البرمجية مثل زر "Step In"، ولكن إذا كان السطر التالي من الشيفرة البرمجية هو استدعاء دالة، فسيتجاوز زر "Step Over" الشيفرة البرمجية الموجودة في هذه الدالة، حيث ستُنفَّذ الشيفرة البرمجية الخاصة بالدالة بالسرعة القصوى، وسيتوقّف منقّح الأخطاء بعد العودة من استدعاء هذه الدالة. إذا استدعى السطر التالي من الشيفرة البرمجية الدالة <code>spam()‎</code> مثلًا، ولكنك لا تهتم بالشيفرة البرمجية الموجودة ضمن هذه الدالة، فيمكنك النقر على زر "Step Over" لتنفيذ الشيفرة البرمجية الموجودة في الدالة بالسرعة العادية ثم التوقف عندما تعود الدالة، لذلك يُعَد استخدام زر "Step Over" أكثر شيوعًا من استخدام زر "Step In".
</p>

<h3 id="stepout">
	زر Step Out
</h3>

<p>
	يؤدي النقر على زر "Step Out" إلى أن ينفّذ منقّح الأخطاء سطورًا من الشيفرة البرمجية بالسرعة القصوى حتى العودة من الدالة الحالية. إذا دخلتَ في استدعاء دالة باستخدام زر "Step In" وتريد الاستمرار في تنفيذ التعليمات حتى الخروج منها، فانقر على زر "Step Out" للخروج من استدعاء الدالة الحالي.
</p>

<h3 id="stop">
	زر التوقف Stop
</h3>

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

<h3 id="-4">
	تنقيح أخطاء برنامج لجمع الأعداد
</h3>

<p>
	افتح تبويبًا جديدًا في محرّرك لإنشاء ملف جديد وأدخِل الشيفرة البرمجية التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_55" style=""><span class="kwd">print</span><span class="pun">(</span><span class="str">'Enter the first number to add:'</span><span class="pun">)</span><span class="pln">
first </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Enter the second number to add:'</span><span class="pun">)</span><span class="pln">
second </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Enter the third number to add:'</span><span class="pun">)</span><span class="pln">
third </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'The sum is '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> first </span><span class="pun">+</span><span class="pln"> second </span><span class="pun">+</span><span class="pln"> third</span><span class="pun">)</span></pre>

<p>
	احفظ البرنامج بالاسم buggyAddingProgram.py وشغّله أولًا دون تفعيل منقّح الأخطاء، وسيكون خرج البرنامج كما يلي:
</p>

<pre class="ipsCode">Enter the first number to add:
5
Enter the second number to add:
3
Enter the third number to add:
42
The sum is 5342
</pre>

<p>
	لم يتعطل البرنامج، ولكن من الواضح أن ناتج الجمع خاطئ. شغّل البرنامج مرة أخرى ولكن مع منقّح الأخطاء هذه المرة، حيث إذا نقرتَ على زر تنقيح الأخطاء "Debug"، فسيتوقف البرنامج مؤقتًا عند السطر 1، وهو سطر الشيفرة البرمجية الذي نوشك على تنفيذه، إذ يجب أن يبدو المحرّر Mu كما في الشكل السابق. انقر على زر "Step Over" مرة واحدة لتنفيذ الاستدعاء الأول <code>print()‎</code>، إذ يجب أن تستخدم زر "Step Over" بدلًا من زر "Step In" هنا، لأنك لا تريد الدخول إلى الشيفرة البرمجية الخاصة بالدالة <code>print()‎</code>، بالرغم من أن المحرّر Mu يجب أن يمنع منقّح الأخطاء من الدخول إلى دوال بايثون المُدمَجة. ينتقل منقّح الأخطاء إلى السطر 2، ويميّز السطر 2 في محرر الملفات كما هو موضح في الشكل التالي، مما يوضّح لك مكان تنفيذ البرنامج حاليًا:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="152720" href="https://academy.hsoub.com/uploads/monthly_2024_07/02_000144.jpg.5c4b4b132c2f962fbdef4e82c2342c36.jpg" rel=""><img alt="02 000144" class="ipsImage ipsImage_thumbnailed" data-fileid="152720" data-unique="tmrce3kdk" src="https://academy.hsoub.com/uploads/monthly_2024_07/02_000144.jpg.5c4b4b132c2f962fbdef4e82c2342c36.jpg"> </a>
</p>

<p style="text-align: center;">
	نافذة المحرّر Mu بعد النقر على زر "Step Over"
</p>

<p>
	انقر على زر "Step Over" مرة أخرى لتنفيذ استدعاء الدالة <code>input()‎</code>، حيث سيختفي التمييز عن الشيفرة البرمجية أثناء انتظار المحرّر Mu أن تكتب شيئًا ما لاستدعاء الدالة <code>input()‎</code> في نافذة الخرج. أدخِل القيمة 5 واضغط على مفتاح <code>ENTER</code>، ثم سيعود التمييز إلى الشيفرة البرمجية.
</p>

<p>
	استمر في النقر على زر "Step Over"، وأدخِل القيمتين 3 و 42 بوصفهما العددين التاليين. يجب أن تبدو نافذة المحرّر Mu كما في الشكل التالي عندما يصل منقّح الأخطاء إلى السطر 7 الذي يمثّل استدعاء الدالة <code>print()‎</code> النهائي في البرنامج:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="152721" href="https://academy.hsoub.com/uploads/monthly_2024_07/03_000086.jpg.3c530aad2c8b94a1ae5951cf2276e180.jpg" rel=""><img alt="03 000086" class="ipsImage ipsImage_thumbnailed" data-fileid="152721" data-unique="qi27muuja" src="https://academy.hsoub.com/uploads/monthly_2024_07/03_000086.jpg.3c530aad2c8b94a1ae5951cf2276e180.jpg"> </a>
</p>

<p>
	توضّح نافذة فحص تنقيح الأخطاء Debug Inspector الموجودة على الجانب الأيمن أن المتغيرات مضبوطة بوصفها سلاسلًا نصية وليست أعدادًا صحيحة، مما تسبّب في حدوث الخطأ
</p>

<p>
	يجب أن ترى في نافذة فحص تنقيح الأخطاء Debug Inspector أن المتغيرات <code>first</code> و <code>second</code> و <code>third</code> مضبوطة بوصفها سلاسلًا نصية <code>'5'</code> و <code>'3'</code> و <code>'42'</code> بدلًا من الأعداد الصحيحة 5 و 3 و 42. تضم لغة بايثون هذه السلاسل النصية مع بعضها بعضًا عند تنفيذ السطر الأخير بدلًا من جمع هذه الأعداد، مما يتسبّب في حدوث الخطأ.
</p>

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

<h3 id="breakpoints">
	نقاط التوقف Breakpoints
</h3>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_57" style=""><span class="kwd">import</span><span class="pln"> random
heads </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</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">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1001</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"> random</span><span class="pun">.</span><span class="pln">randint</span><span class="pun">(</span><span class="lit">0</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="lit">1</span><span class="pun">:</span><span class="pln">
         heads </span><span class="pun">=</span><span class="pln"> heads </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
     </span><span class="kwd">if</span><span class="pln"> i </span><span class="pun">==</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"> </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Halfway done!'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Heads came up '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">heads</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">' times.'</span><span class="pun">)</span></pre>

<p>
	سيعيد الاستدعاء <code>random.randint(0, 1)‎</code> ➊ القيمة 0 في نصف الوقت والقيمة 1 في النصف الآخر من الوقت، حيث يمكن استخدام هذا الاستدعاء لمحاكاة رمي قطعة نقود وفق الاحتمال 50/50 وتمثل القيمة 1 الصورة من العملة المعدنية. يكون خرج هذا البرنامج كما يلي عند تشغيله بدون منقّح الأخطاء:
</p>

<pre class="ipsCode">Halfway done!
Heads came up 490 times.
</pre>

<p>
	إذا شغّلتَ هذا البرنامج مع منقّح الأخطاء، فيجب أن تنقر على زر "Step Over" آلاف المرات قبل إنهاء البرنامج. إذا كنت مهتمًا بالقيمة <code>heads</code> التي تمثّل صورة العملة المعدنية عند منتصف تنفيذ البرنامج أو عند اكتمال 500 مرة من 1000 مرة لرمي قطعة نقود، فيمكنك ضبط نقطة توقف على السطر <code>print('Halfway done!')‎</code> ➋، حيث يمكنك ضبط نقطة توقف من خلال النقر على رقم السطر في محرّر الملفات بحيث تظهر نقطة حمراء كما في الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="152722" href="https://academy.hsoub.com/uploads/monthly_2024_07/04_000124.jpg.ec0b9143e605ee598c6b9ff870e9b368.jpg" rel=""><img alt="04 000124" class="ipsImage ipsImage_thumbnailed" data-fileid="152722" data-unique="hl2oiohv6" src="https://academy.hsoub.com/uploads/monthly_2024_07/04_000124.jpg.ec0b9143e605ee598c6b9ff870e9b368.jpg"> </a>
</p>

<p>
	يؤدي ضبط نقطة التوقف إلى ظهور نقطة حمراء (محاطة بدائرة) بجانب رقم السطر
</p>

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

<p>
	سيكون للسطر الذي يحتوي على نقطة التوقف نقطة حمراء بجانبه. إذا شغّلنا البرنامج مع منقّح الأخطاء، فسيبدأ في حالة التوقّف المؤقت عند السطر الأول كالمعتاد، ولكن إذا نقرت على زر المتابعة "Continue"، فسيُشغَّل البرنامج بالسرعة القصوى حتى يصل إلى السطر الذي ضبطنا نقطة التوقف عنده. يمكنك بعد ذلك النقر على أزرار "Continue" أو "Step Over" أو "Step In" أو "Step Out" للمتابعة كالمعتاد.
</p>

<p>
	إذا أردتَ إزالة نقطة توقف، فانقر على رقم السطر مرة أخرى، وستختفي النقطة الحمراء، ولن يتوقف منقّح الأخطاء عند هذا السطر لاحقًا.
</p>

<h2 id="-6">
	مشروع للتدريب
</h2>

<p>
	حاول كتابة برنامج يطبّق ما يلي لكسب خبرة عملية أكبر.
</p>

<h3 id="-7">
	تنقيح أخطاء برنامج لرمي عملة معدنية
</h3>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5086_59" style=""><span class="kwd">import</span><span class="pln"> random
guess </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> guess </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">(</span><span class="str">'heads'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'tails'</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Guess the coin toss! Enter heads or tails:'</span><span class="pun">)</span><span class="pln">
    guess </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
toss </span><span class="pun">=</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">randint</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="com"># تمثّل القيمة 0 الكتابة، وتمثل القيمة 1 الصورة في العملة المعدنية</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> toss </span><span class="pun">==</span><span class="pln"> guess</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You got it!'</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="str">'Nope! Guess again!'</span><span class="pun">)</span><span class="pln">
    guesss </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> toss </span><span class="pun">==</span><span class="pln"> guess</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You got it!'</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="str">'Nope. You are really bad at this game.'</span><span class="pun">)</span></pre>

<h2 id="-8">
	الخلاصة
</h2>

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

<p>
	يمكن اكتشاف الاستثناء ومعالجته باستخدام تعليمات <code>try</code> و <code>except</code>. تُعَد الوحدة <code>logging</code> طريقة جيدة لتفحّص شيفرتك البرمجية أثناء تشغيلها، وهي أكثر ملاءمة للاستخدام من الدالة <code>print()‎</code> لاحتوائها على مستويات تسجيل متعددة ولقدرتها على التسجيل في ملف نصي.
</p>

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

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

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://automatetheboringstuff.com/2e/chapter11/" rel="external nofollow">Debugging</a> لصاحبه Al Sweigart.
</p>

<h2 id="-9">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/python/%D8%AA%D9%86%D8%B8%D9%8A%D9%85-%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%A7%D9%8A%D8%AB%D9%88%D9%86-r2358/" rel="">تنظيم الملفات باستخدام بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%B4%D9%8A%D9%81%D8%B1%D8%A7%D8%AA-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%B5%D9%8A%D8%BA-%D8%B4%D8%A7%D8%A6%D8%B9%D8%A9-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B9%D9%84%D9%89-%D9%86%D8%AD%D9%88-%D8%AE%D8%A7%D8%B7%D8%A6-r1971/" rel="">كتابة شيفرات بايثون: صيغ شائعة الاستخدام على نحو خاطئ</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%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-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1815/" rel="">أساسيات البرمجة بلغة بايثون</a>
	</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>
</ul>
]]></description><guid isPermaLink="false">2359</guid><pubDate>Thu, 11 Jul 2024 15:08:02 +0000</pubDate></item><item><title>&#x62A;&#x646;&#x638;&#x64A;&#x645; &#x627;&#x644;&#x645;&#x644;&#x641;&#x627;&#x62A; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646;</title><link>https://academy.hsoub.com/programming/python/%D8%AA%D9%86%D8%B8%D9%8A%D9%85-%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%A7%D9%8A%D8%AB%D9%88%D9%86-r2358/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_07/---.png.006cbcd9f28aa4deef29949a368a5773.png" /></p>
<p>
	تعلّمنا في <a href="https://academy.hsoub.com/programming/python/%D9%82%D8%B1%D8%A7%D8%A1%D8%A9-%D9%88%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%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-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2347/" rel="">مقالٍ سابق</a> كيفية إنشاء ملفات جديدة والكتابة فيها باستخدام <a href="https://academy.hsoub.com/programming/python/" rel="">لغة بايثون Python</a>، ويمكن لبرامجك أيضًا تنظيم الملفات الموجودة مسبقًا على القرص الصلب. لا بد أنك جرّبتَ تصفح مجلدٍ مليء بالعشرات أو المئات أو حتى الآلاف من الملفات ونسخها أو إعادة تسميتها أو نقلها أو ضغطها جميعًا يدويًا، أو جرّبتَ مهامًا أخرى مثل المهام التالية:
</p>

<ul>
	<li>
		إنشاء نُسخ من جميع ملفات PDF الموجودة في كل مجلدٍ فرعي من مجلدٍ ما.
	</li>
	<li>
		إزالة الأصفار البادئة في أسماء الملفات لكل ملفٍ في مجلد يضم مئات الملفات المسمّاة مثلًا spam001.txt و spam002.txt وإلخ.
	</li>
	<li>
		ضغط محتويات عدة مجلدات في ملف مضغوط ZIP واحد، والذي يمكن أن يكون نظام <a href="https://academy.hsoub.com/apps/general/%D8%A7%D9%84%D9%86%D8%B3%D8%AE-%D8%A7%D9%84%D8%A7%D8%AD%D8%AA%D9%8A%D8%A7%D8%B7%D9%8A-%D9%88%D8%AD%D9%81%D8%B8-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A7%D9%84%D8%B9%D8%A7%D9%84%D9%85-%D8%A7%D9%84%D8%B1%D9%82%D9%85%D9%8A-r375/" rel="">نسخ احتياطي</a> بسيط.
	</li>
</ul>

<p>
	يمكنك تنفيذ كافة هذه المهام المملة آليًا في شيفرة <a href="https://academy.hsoub.com/programming/python/%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-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1815/" rel="">بايثون</a> البرمجية، فإذا برمجتَ حاسوبك لإجراء هذه المهام، فيمكنك تحويله إلى محرر ملفات سريع في العمل ولا يرتكب أخطاءً أبدًا.
</p>

<p>
	من المفيد رؤية امتداد الملف (مثل <code>‎.txt</code> و <code>‎.pdf</code> و <code>‎.jpg</code> وإلخ) بسرعة عند بدء العمل مع الملفات، إذ يُرجَّح أن يعرض متصفح ملفاتك الامتدادات تلقائيًا في نظامي ماك macOS و<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%86%D8%B8%D8%A7%D9%85-%D9%84%D9%8A%D9%86%D9%83%D8%B3-linux-%D9%88%D8%A3%D8%A8%D8%B1%D8%B2-%D9%85%D9%85%D9%8A%D8%B2%D8%A7%D8%AA%D9%87-%D9%88%D8%B9%D9%8A%D9%88%D8%A8%D9%87-r2252/" rel="">لينكس Linux</a>، ولكن قد تكون امتدادات الملفات مخفية افتراضيًا في نظام ويندوز Windows، لذا يمكنك إظهار الامتدادات من خلال الانتقال إلى قائمة ابدأ Start، ثم لوحة التحكم Control Panel، ثم المظهر وإضفاء طابع شخصي Appearance and Personalization، ثم خيارات مستكشف الملفات Folder Options. ألغِ تحديد خانة الاختيار إخفاء ملحقات الملفات لأنواع الملفات المعروفة Hide extensions for known file types في تبويب عرض View ضمن الإعدادات المتقدمة Advanced Settings.
</p>

<h2 id="shutil">
	وحدة shutil
</h2>

<p>
	تحتوي وحدة <code>shutil</code> (التي هي اختصار لأدوات الصدفة المساعدة Shell Utilities) على دوالٍ تتيح لك نسخ الملفات ونقلها وإعادة تسميتها وحذفها في برامج بايثون الخاصة بك، ولكن يجب أولًا أن تستخدم التعليمة <code>import shutil</code> لاستخدام هذه <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2336/" rel="">الدوال</a>.
</p>

<h3 id="">
	نسخ الملفات والمجلدات
</h3>

<p>
	توفّر وحدة <code>shutil</code> دوالًا لنسخ الملفات والمجلدات الكاملة، حيث سيؤدي استدعاء الدالة <code>shutil.copy(source, destination)‎</code> إلى نسخ الملف من مسار المصدر <code>source</code> إلى المجلد الموجود في مسار الوِجهة <code>destination</code>، إذ يمكن أن يكون كلٌّ من <code>source</code> و <code>destination</code> سلاسلًا نصية أو كائنات <code>Path</code>. إذا كان <code>destination</code> اسم ملف، فسنستخدمه بوصفه اسمًا جديدًا للملف المنسوخ. تعيد هذه الدالة سلسلة نصية أو كائن <code>Path</code> للملف المنسوخ.
</p>

<p>
	أدخِل مثلًا ما يلي في الصدفة التفاعلية Interactive Shell لترى كيفية عمل الدالة <code>shutil.copy()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_8" style=""><span class="pln">   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> shutil</span><span class="pun">,</span><span class="pln"> os
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> pathlib </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Path</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> p </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">home</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"> shutil</span><span class="pun">.</span><span class="pln">copy</span><span class="pun">(</span><span class="pln">p </span><span class="pun">/</span><span class="pln"> </span><span class="str">'spam.txt'</span><span class="pun">,</span><span class="pln"> p </span><span class="pun">/</span><span class="pln"> </span><span class="str">'some_folder'</span><span class="pun">)</span><span class="pln">
   </span><span class="str">'C:\\Users\\Al\\some_folder\\spam.txt'</span><span class="pln">
</span><span class="pun">➋</span><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> shutil</span><span class="pun">.</span><span class="pln">copy</span><span class="pun">(</span><span class="pln">p </span><span class="pun">/</span><span class="pln"> </span><span class="str">'eggs.txt'</span><span class="pun">,</span><span class="pln"> p </span><span class="pun">/</span><span class="pln"> </span><span class="str">'some_folder/eggs2.txt'</span><span class="pun">)</span><span class="pln">
   </span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/some_folder/eggs2.txt'</span><span class="pun">)</span></pre>

<p>
	ينسخ استدعاء الدالة <code>shutil.copy()‎</code> الأول الملف الموجود في <code>C:\Users\Al\spam.txt</code> إلى المجلد <code>C:\Users\Al\some_folder</code>، وتكون القيمة المُعادة هي مسار الملف المنسوخ، ولاحظ استخدام اسم الملف spam.txt الأصلي لاسم الملف المنسوخ الجديد عند تحديد مجلدٍ بوصفه الوِجهة ➊. ينسخ استدعاء الدالة <code>shutil.copy()‎</code> الثاني ➋ الملف الموجود في <code>C:\Users\Al\eggs.txt</code> إلى المجلد <code>C:\Users\Al\some_folder</code>، ولكنه يعطي الملف المنسوخ الاسم eggs2.txt.
</p>

<p>
	تنسخ الدالة <code>shutil.copy()‎</code> ملفًا واحدًا، وتنسخ الدالة <code>shutil.copytree()‎</code> مجلدًا كاملًا مع جميع المجلدات والملفات الموجودة فيه، حيث يؤدي استدعاء الدالة <code>shutil.copytree(source, destination)‎</code> إلى نسخ المجلد الموجود في مسار المصدر <code>source</code> مع جميع ملفاته ومجلداته الفرعية إلى المجلد الموجود في مسار الوِجهة <code>destination</code>، إذ تكون المعاملات <code>source</code> و <code>destination</code> سلاسلًا نصية. تعيد هذه الدالة سلسلة نصية تمثّل مسار المجلد المنسوخ.
</p>

<p>
	لندخِل مثلًا ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_10" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> shutil</span><span class="pun">,</span><span class="pln"> os
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> pathlib </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Path</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> p </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">home</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> shutil</span><span class="pun">.</span><span class="pln">copytree</span><span class="pun">(</span><span class="pln">p </span><span class="pun">/</span><span class="pln"> </span><span class="str">'spam'</span><span class="pun">,</span><span class="pln"> p </span><span class="pun">/</span><span class="pln"> </span><span class="str">'spam_backup'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/spam_backup'</span><span class="pun">)</span></pre>

<p>
	ينشئ استدعاء الدالة <code>shutil.copytree()‎</code> السابق مجلدًا جديدًا بالاسم spam_backup الذي يحتوي على محتوى المجلد spam الأصلي نفسه، وبالتالي سنحصل بأمان على نسخة احتياطية من المجلد spam.
</p>

<h3 id="-1">
	نقل وإعادة تسمية الملفات والمجلدات
</h3>

<p>
	سيؤدي استدعاء الدالة <code>shutil.move(source, destination)‎</code> إلى نقل الملف أو المجلد الموجود في مسار المصدر <code>source</code> إلى مسار الوجهة <code>destination</code>، وسيعيد سلسلة نصية للمسار المطلق الخاص بالموقع الجديد.
</p>

<p>
	إذا أشار مسار الوجهة <code>destination</code> إلى مجلد، فسيُنقَل ملف المصدر <code>source</code> إلى الوجهة <code>destination</code> ويحتفظ باسم الملف الحالي. لندخِل مثلًا ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_12" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> shutil
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> shutil</span><span class="pun">.</span><span class="pln">move</span><span class="pun">(</span><span class="str">'C:\\beef.txt'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'C:\\eggs'</span><span class="pun">)</span><span class="pln">
</span><span class="str">'C:\\eggs\\beef.txt'</span></pre>

<p>
	لنفترض أن المجلد الذي اسمه eggs موجودٌ مسبقًا في المجلد ‎<code>C:\</code>‎، فسيمثّل استدعاء الدالة ‎<code>shutil.move()</code>‎ نقلَ الملف <code>C:\beef.txt</code> إلى المجلد <code>C:\eggs</code>. إذا كان الملف beef.txt موجودًا مسبقًا في المجلد <code>C:\eggs</code>، فسيُكتَب فوقه، لذا يجب عليك توخي الحذر عند استخدام الدالة <code>move()‎</code> لأنه من السهل الكتابة فوق الملفات عن طريق الخطأ باستخدام هذه الطريقة.
</p>

<p>
	يمكن لمسار الوِجهة <code>destination</code> أيضًا تحديد اسم الملف، حيث سننقل ملف المصدر <code>source</code> ونعيد تسميته في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_14" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> shutil</span><span class="pun">.</span><span class="pln">move</span><span class="pun">(</span><span class="str">'C:\\beef.txt'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'C:\\eggs\\new_beef.txt'</span><span class="pun">)</span><span class="pln">
</span><span class="str">'C:\\eggs\\new_beef.txt'</span></pre>

<p>
	يمثّل السطر السابق نقل الملف <code>C:\beef.txt</code> إلى المجلد <code>C:\eggs</code> وإعادة تسميته بالاسم new_beef.txt.
</p>

<p>
	نفترض في المثالين السابقين وجود المجلد eggs في المجلد ‎<code>C:\</code>‎، ولكن إن لم يوجَد المجلد eggs، فستعيد الدالة <code>move()‎</code> تسمية الملف beef.txt إلى ملفٍ اسمه eggs.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_16" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> shutil</span><span class="pun">.</span><span class="pln">move</span><span class="pun">(</span><span class="str">'C:\\beef.txt'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'C:\\eggs'</span><span class="pun">)</span><span class="pln">
</span><span class="str">'C:\\eggs'</span></pre>

<p>
	لم تتمكّن الدالة <code>move()‎</code> من العثور على مجلدٍ بالاسم eggs في المجلد C:\‎، وبالتالي تفترض أن الوجهة <code>destination</code> يجب أن تحدد اسم ملفٍ وليس اسم مجلد، لذلك أُعيدت تسمية الملف النصي beef.txt إلى egg (ملف نصي بدون امتداد الملف <code>‎.txt</code>)، وربما ليس هذا ما أردته. يمكن أن يكون ذلك خطأً يصعب اكتشافه في برامجك، لأن استدعاء الدالة <code>move()‎</code> يمكن أن يفعل شيئًا قد يكون مختلفًا تمامًا عمّا تتوقعه، وهذا سبب آخر لتوخي الحذر عند استخدام الدالة <code>move()‎</code>.
</p>

<p>
	أخيرًا، يجب أن تكون المجلدات التي تشكّل الوِجهة موجودة فعليًا، وإلّا فسترمي شيفرة بايثون استثناءً. لندخِل الآن ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_18" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> shutil</span><span class="pun">.</span><span class="pln">move</span><span class="pun">(</span><span class="str">'spam.txt'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'c:\\does_not_exist\\eggs\\meat'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">
</span><span class="typ">FileNotFoundError</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="typ">Errno</span><span class="pln"> </span><span class="lit">2</span><span class="pun">]</span><span class="pln"> </span><span class="typ">No</span><span class="pln"> such file </span><span class="kwd">or</span><span class="pln"> directory</span><span class="pun">:</span><span class="pln"> </span><span class="str">'c:\\does_not_exist\\
eggs\\meat'</span></pre>

<p>
	تبحث شيفرة بايثون عن المجلدين eggs و meat ضمن المجلد does_not_exist، ولكنها لا تعثر على هذا المجلد، لذا لا يمكنها نقل الملف spam.txt إلى المسار الذي حدّدته.
</p>

<h3 id="-2">
	حذف الملفات والمجلدات نهائيًا
</h3>

<p>
	يمكنك حذف ملف واحد أو مجلد واحد فارغ باستخدام دوال تابعة للوحدة <code>os</code>، ولكن يمكنك حذف مجلدٍ وجميع محتوياته باستخدام الوحدة <code>shutil</code>، وهذه الدوال هي:
</p>

<ul>
	<li>
		سيؤدي استدعاء الدالة <code>os.unlink(path)‎</code> إلى حذف الملف الموجود في المسار <code>path</code>.
	</li>
	<li>
		سيؤدي استدعاء الدالة <code>os.rmdir(path)‎</code> إلى حذف المجلد الموجود في المسار <code>path</code>، ولكن يجب أن يكون هذا المجلد خاليًا من أي ملفات أو مجلدات.
	</li>
	<li>
		سيؤدي استدعاء الدالة <code>shutil.rmtree(path)‎</code> إلى إزالة المجلد الموجود في المسار <code>path</code>، وستُحذَف جميع الملفات والمجلدات الموجودة ضمنه.
	</li>
</ul>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_20" style=""><span class="kwd">import</span><span class="pln"> os
</span><span class="kwd">from</span><span class="pln"> pathlib </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Path</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> filename </span><span class="kwd">in</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">home</span><span class="pun">().</span><span class="pln">glob</span><span class="pun">(</span><span class="str">'*.rxt'</span><span class="pun">):</span><span class="pln">
    os</span><span class="pun">.</span><span class="pln">unlink</span><span class="pun">(</span><span class="pln">filename</span><span class="pun">)</span></pre>

<p>
	إذا كان لديك أيّ ملفات مهمة تنتهي بالامتداد <code>‎.rxt</code> فستُحذَف نهائيًا عن طريق الخطأ، لذا يجب أولًا أن تشغّل البرنامج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_22" style=""><span class="kwd">import</span><span class="pln"> os
</span><span class="kwd">from</span><span class="pln"> pathlib </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Path</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> filename </span><span class="kwd">in</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">home</span><span class="pun">().</span><span class="pln">glob</span><span class="pun">(</span><span class="str">'*.rxt'</span><span class="pun">):</span><span class="pln">
    </span><span class="com">#os.unlink(filename)</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">filename</span><span class="pun">)</span></pre>

<p>
	لاحظ أننا علّقنا استدعاء الدالة <code>os.unlink()‎</code>، لذا تجاهلته شيفرة بايثون، وستطبع اسم الملف المحذوف فقط، حيث سيؤدي تشغيل هذه النسخة من البرنامج أولًا إلى إظهار أنك طلبت من البرنامج عن طريق الخطأ حذف ملفات <code>‎.rxt</code> بدلًا من ملفات <code>‎.txt</code>.
</p>

<p>
	تأكّد من عمل البرنامج بالطريقة الصحيحة، ثم احذف سطر التعليمة <code>print(filename)‎</code> وألغِ التعليق عند سطر التعليمة <code>os.unlink(filename)‎</code>، ثم شغّل البرنامج مرة أخرى لحذف الملفات فعليًا.
</p>

<h3 id="send2trash">
	الحذف الآمن باستخدام وحدة send2trash
</h3>

<p>
	تحذف الدالة <code>shutil.rmtree()‎</code> المُدمَجة مع لغة بايثون الملفات والمجلدات نهائيًا، ولكن قد يكون استخدامها خطيرًا، لذا توجد طريقة أفضل بكثير لحذف الملفات والمجلدات، وهي استخدام الوحدة <code>send2trash</code> الخارجية. يمكنك تثبيت هذه الوحدة من خلال تشغيل الأمر <code>pip install --user send2trash</code> من نافذة الطرفية Terminal.
</p>

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

<p>
	أدخِل مثلًا ما يلي في الصدفة التفاعلية بعد تثبيت الوحدة <code>send2trash</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_24" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> send2trash
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> beefFile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'beef.txt'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'a'</span><span class="pun">)</span><span class="pln">   </span><span class="com"># إنشاء الملف</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> beefFile</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">'Beef is not a vegetable.'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">25</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> beefFile</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> send2trash</span><span class="pun">.</span><span class="pln">send2trash</span><span class="pun">(</span><span class="str">'beef.txt'</span><span class="pun">)</span></pre>

<p>
	يجب دائمًا أن تستخدم الدالة <code>send2trash.send2trash()‎</code> لحذف الملفات والمجلدات، ولكن بالرغم من أن إرسال الملفات إلى سلة المحذوفات يتيح لك استعادتها لاحقًا، إلّا أنه لن يؤدي إلى تحرير مساحةٍ من القرص الصلب كما يفعل الحذف النهائي، لذا إذا أردتَ أن يحرّر برنامجك مساحةً من القرص الصلب، فاستخدم دوال الوحدتين <code>os</code> و <code>shutil</code> لحذف الملفات والمجلدات. لاحظ أن الدالة <code>send2trash()‎</code> يمكنها إرسال الملفات إلى سلة المحذوفات فقط، ولا يمكنها سحب الملفات منها.
</p>

<h2 id="-3">
	المرور على شجرة مجلدات
</h2>

<p>
	لنفترض أنك تريد إعادة تسمية كل ملف في مجلدٍ ما وكل ملفٍ في كل مجلدٍ فرعي من هذا المجلد، وهذا يعني أنك تريد المرور على شجرة المجلدات، والتفاعل مع جميع الملفات أثناء المرور عليها. قد تكون كتابة برنامجٍ لذلك أمرًا صعبًا، ولكن توفّر بايثون الدالة <code>os.walk()‎</code> للتعامل مع هذه العملية نيابةً عنك.
</p>

<p>
	أولًا، لنلقِ نظرة على المجلد <code>C:\delicious</code> ومحتوياته كما هو موضح في الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="152715" href="https://academy.hsoub.com/uploads/monthly_2024_07/01_000047.jpg.22579207f9bd414df6dc93c3488a730c.jpg" rel=""><img alt="01 000047" class="ipsImage ipsImage_thumbnailed" data-fileid="152715" data-unique="v345wmq3m" src="https://academy.hsoub.com/uploads/monthly_2024_07/01_000047.jpg.22579207f9bd414df6dc93c3488a730c.jpg"> </a>
</p>

<p>
	مثال لمجلد يحتوي على ثلاثة مجلدات وأربعة ملفات
</p>

<p>
	إليك فيما يلي مثال لبرنامج يستخدم الدالة <code>os.walk()‎</code> مع شجرة المجلدات من الشكل السابق:
</p>

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

</span><span class="kwd">for</span><span class="pln"> folderName</span><span class="pun">,</span><span class="pln"> subfolders</span><span class="pun">,</span><span class="pln"> filenames </span><span class="kwd">in</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">walk</span><span class="pun">(</span><span class="str">'C:\\delicious'</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'The current folder is '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> folderName</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> subfolder </span><span class="kwd">in</span><span class="pln"> subfolders</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'SUBFOLDER OF '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> folderName </span><span class="pun">+</span><span class="pln"> </span><span class="str">': '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> subfolder</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> filename </span><span class="kwd">in</span><span class="pln"> filenames</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'FILE INSIDE '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> folderName </span><span class="pun">+</span><span class="pln"> </span><span class="str">': '</span><span class="pun">+</span><span class="pln"> filename</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span></pre>

<p>
	نمرّر قيمة سلسلة نصية واحدة تمثّل مسار المجلد إلى الدالة <code>os.walk()‎</code> التي يمكنك استخدامها في تعليمة <a href="https://wiki.hsoub.com/Python/for" rel="external">حلقة for</a> للمرور على شجرة المجلدات، حيث يشبه ذلك استخدام الدالة <code>range()‎</code> للمرور على مجالٍ من الأعداد، ولكن ستعيد الدالة <code>os.walk()‎</code> ثلاث قيم في كل تكرار من هذه الحلقة، وهذه القيم هي:
</p>

<ul>
	<li>
		سلسلة نصية تمثّل اسم المجلد الحالي.
	</li>
	<li>
		قائمة من السلاسل النصية التي تمثّل المجلدات الموجودة في المجلد الحالي.
	</li>
	<li>
		قائمة من السلاسل النصية التي تمثّل الملفات الموجودة في المجلد الحالي.
	</li>
</ul>

<p>
	<strong>ملاحظة</strong>: المجلد الحالي هو المجلد الخاص بالتكرار الحالي لحلقة <code>for</code>، ولم تغيّر الدالة <code>os.walk()‎</code> مجلد العمل الحالي للبرنامج.
</p>

<p>
	يمكنك اختيار اسم المتغير <code>i</code> في شيفرة <code>for i in range(10):‎</code>، ويمكنك أيضًا اختيار أسماء المتغيرات للقيم الثلاث المذكورة سابقًا، ولكننا سنستخدم أسماء المتغيرات <code>foldername</code> و <code>subfolders</code> و <code>filenames</code> في أغلب الأحيان.
</p>

<p>
	إذا شغّلنا البرنامج، فسينتج ما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_28" style=""><span class="typ">The</span><span class="pln"> current folder </span><span class="kwd">is</span><span class="pln"> C</span><span class="pun">:</span><span class="pln">\delicious
SUBFOLDER OF C</span><span class="pun">:</span><span class="pln">\delicious</span><span class="pun">:</span><span class="pln"> cats
SUBFOLDER OF C</span><span class="pun">:</span><span class="pln">\delicious</span><span class="pun">:</span><span class="pln"> walnut
FILE INSIDE C</span><span class="pun">:</span><span class="pln">\delicious</span><span class="pun">:</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">txt

</span><span class="typ">The</span><span class="pln"> current folder </span><span class="kwd">is</span><span class="pln"> C</span><span class="pun">:</span><span class="pln">\delicious\cats
FILE INSIDE C</span><span class="pun">:</span><span class="pln">\delicious\cats</span><span class="pun">:</span><span class="pln"> catnames</span><span class="pun">.</span><span class="pln">txt
FILE INSIDE C</span><span class="pun">:</span><span class="pln">\delicious\cats</span><span class="pun">:</span><span class="pln"> zophie</span><span class="pun">.</span><span class="pln">jpg

</span><span class="typ">The</span><span class="pln"> current folder </span><span class="kwd">is</span><span class="pln"> C</span><span class="pun">:</span><span class="pln">\delicious\walnut
SUBFOLDER OF C</span><span class="pun">:</span><span class="pln">\delicious\walnut</span><span class="pun">:</span><span class="pln"> waffles

</span><span class="typ">The</span><span class="pln"> current folder </span><span class="kwd">is</span><span class="pln"> C</span><span class="pun">:</span><span class="pln">\delicious\walnut\waffles
FILE INSIDE C</span><span class="pun">:</span><span class="pln">\delicious\walnut\waffles</span><span class="pun">:</span><span class="pln"> butter</span><span class="pun">.</span><span class="pln">txt</span><span class="pun">.</span></pre>

<p>
	تعيد الدالة <code>os.walk()‎</code> قوائمًا من السلاسل النصية التي تمثّل المتغيرات <code>subfolder</code> و <code>filename</code>، لذا يمكنك استخدام هذه القوائم في حلقات <code>for</code> الخاصة بها. ضع شيفرتك البرمجية مكان استدعاءات الدالة <code>print()‎</code>، أو احذف حلقتي <code>for</code> إن لم تكن بحاجة إليهما.
</p>

<h2 id="zipfile">
	ضغط الملفات باستخدام الوحدة zipfile
</h2>

<p>
	قد تكون على دراية بالملفات المضغوطة ZIP ذات امتداد الملف <code>‎.zip</code>، والتي يمكنها الاحتفاظ بالمحتويات المضغوطة للعديد من الملفات الأخرى، حيث يؤدي ضغط الملف إلى تقليل حجمه، ويُعَد ذلك أمرًا مفيدًا عند نقله عبر الإنترنت. يمكن أن يحتوي ملف ZIP أيضًا على ملفات ومجلدات فرعية متعددة، لذا تُعَد طريقة سهلة لحَزم ملفات متعددة في ملف واحد، ويمكن بعد ذلك مثلًا إرفاق هذا الملف الذي يسمّى ملف الأرشفة Archive File مع رسالة بريد إلكتروني.
</p>

<p>
	يمكن لبرامج <a href="https://wiki.hsoub.com/Python" rel="external">بايثون</a> الخاص بك إنشاء ملفات ZIP وفتحها (أو فك ضغطها Extract) باستخدام الدوال الموجودة في الوحدة <code>zipfile</code>. لنفترض أن لديك ملف ZIP بالاسم example.zip ويحتوي على المحتويات الموضّحة في الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="152714" href="https://academy.hsoub.com/uploads/monthly_2024_07/02_000008.jpg.c37d3ce382c28407b6026e1c4767a600.jpg" rel=""><img alt="02 000008" class="ipsImage ipsImage_thumbnailed" data-fileid="152714" data-unique="nrbiegz70" src="https://academy.hsoub.com/uploads/monthly_2024_07/02_000008.jpg.c37d3ce382c28407b6026e1c4767a600.jpg"> </a>
</p>

<p style="text-align: center;">
	محتويات الملف example.zip
</p>

<p>
	يمكنك تنزيل هذا الملف من موقع <a href="https://nostarch.com/automatestuff2/" rel="external nofollow">nostarch</a> أو المتابعة باستخدام ملف ZIP موجود مسبقًا على حاسوبك.
</p>

<h3 id="zip">
	قراءة الملفات المضغوطة ZIP
</h3>

<p>
	يمكنك قراءة محتويات ملف مضغوط ZIP من خلال إنشاء كائن <code>ZipFile</code> أولًا (لاحظ الأحرف الكبيرة Z و F)، حيث تتشابه كائنات <code>ZipFile</code> مع كائنات <code>File</code> التي تعيدها الدالة <code>open()‎</code>، فهي قيم يتفاعل البرنامج من خلالها مع الملف. ننشئ كائن <code>ZipFile</code> من خلال استدعاء الدالة <code>zipfile.ZipFile()‎</code> وتمرير سلسلة نصية تمثّل اسم ملف <code>‎.ZIP</code> إليها. لاحظ أن <code>zipfile</code> هو اسم وحدة بايثون، وأن <code>ZipFile()‎</code> هو اسم الدالة.
</p>

<p>
	أدخِل مثلًا ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_30" style=""><span class="pln">   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> zipfile</span><span class="pun">,</span><span class="pln"> os

   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> pathlib </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Path</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> p </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">home</span><span class="pun">()</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> exampleZip </span><span class="pun">=</span><span class="pln"> zipfile</span><span class="pun">.</span><span class="typ">ZipFile</span><span class="pun">(</span><span class="pln">p </span><span class="pun">/</span><span class="pln"> </span><span class="str">'example.zip'</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> exampleZip</span><span class="pun">.</span><span class="pln">namelist</span><span class="pun">()</span><span class="pln">
   </span><span class="pun">[</span><span class="str">'spam.txt'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cats/'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cats/catnames.txt'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cats/zophie.jpg'</span><span class="pun">]</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spamInfo </span><span class="pun">=</span><span class="pln"> exampleZip</span><span class="pun">.</span><span class="pln">getinfo</span><span class="pun">(</span><span class="str">'spam.txt'</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spamInfo</span><span class="pun">.</span><span class="pln">file_size
   </span><span class="lit">13908</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spamInfo</span><span class="pun">.</span><span class="pln">compress_size
   </span><span class="lit">3828</span><span class="pln">
</span><span class="pun">➊</span><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> f</span><span class="str">'Compressed file is {round(spamInfo.file_size / spamInfo
   .compress_size, 2)}x smaller!'</span><span class="pln">
   </span><span class="pun">)</span><span class="pln">
   </span><span class="str">'Compressed file is 3.63x smaller!'</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> exampleZip</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	يحتوي كائن <code>ZipFile</code> على التابع <code>namelist()‎</code> الذي يعيد قائمةً من السلاسل النصية التي تمثّل جميع الملفات والمجلدات الموجودة في ملف ZIP، حيث يمكن تمرير هذه السلاسل النصية إلى التابع <code>getinfo()‎</code> لإعادة كائن <code>ZipInfo</code> لهذا الملف المحدّد. تمتلك كائنات <code>ZipInfo</code> سماتها Attributes الخاصة مثل السمات <code>file_size</code> و <code>compress_size</code> بالبايتات، والتي تحتوي على أعداد صحيحة لحجم الملف الأصلي وحجم الملف المضغوط على التوالي. يمثل كائن <code>ZipInfo</code> ملف أرشفة كامل، ولكن يحمل كائن <code>ZipInfo</code> أيضًا معلومات مفيدة حول ملف واحد في ملف الأرشفة.
</p>

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

<h3 id="zip-1">
	فك ضغط ملفات ZIP
</h3>

<p>
	يفك التابع <code>extractall()‎</code> الخاص بكائنات <code>ZipFile</code> ضغط جميع الملفات والمجلدات من ملف مضغوط ZIP إلى مجلد العمل الحالي.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_32" style=""><span class="pln">   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> zipfile</span><span class="pun">,</span><span class="pln"> os
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> pathlib </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Path</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> p </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">home</span><span class="pun">()</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> exampleZip </span><span class="pun">=</span><span class="pln"> zipfile</span><span class="pun">.</span><span class="typ">ZipFile</span><span class="pun">(</span><span class="pln">p </span><span class="pun">/</span><span class="pln"> </span><span class="str">'example.zip'</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"> exampleZip</span><span class="pun">.</span><span class="pln">extractall</span><span class="pun">()</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> exampleZip</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	يؤدي تشغيل الشيفرة البرمجية السابقة إلى فَك ضغط محتويات الملف example.zip في المجلد ‎<code>C:\</code>‎. يمكنك اختياريًا تمرير اسم مجلد إلى التابع ‎<code>extractall()</code>‎ لفك ضغط الملفات في مجلد آخر مختلفٍ عن مجلد العمل الحالي، وإذا كان المجلد الذي مرّرناه إلى التابع <code>extractall()‎</code> غير موجود، فسيُشَأ هذا المجلد، فمثلًا إذا وضعتَ الاستدعاء <code>exampleZip.extractall('C:\\delicious')‎</code> مكان الاستدعاء ➊، فستفك الشيفرة البرمجية ضغط الملفات من الملف example.zip إلى المجلد <code>C:\delicious</code> الذي أنشأناه.
</p>

<p>
	يفك التابع <code>extract()‎</code> الخاص بكائنات <code>ZipFile</code> ضغط ملفٍ واحد من الملف المضغوط ZIP. تابع مثال الصدفة التفاعلية بما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_34" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> exampleZip</span><span class="pun">.</span><span class="pln">extract</span><span class="pun">(</span><span class="str">'spam.txt'</span><span class="pun">)</span><span class="pln">
</span><span class="str">'C:\\spam.txt'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> exampleZip</span><span class="pun">.</span><span class="pln">extract</span><span class="pun">(</span><span class="str">'spam.txt'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'C:\\some\\new\\folders'</span><span class="pun">)</span><span class="pln">
</span><span class="str">'C:\\some\\new\\folders\\spam.txt'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> exampleZip</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

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

<h3 id="zip-2">
	إنشاء ملفات ZIP والإضافة إليها
</h3>

<p>
	يمكنك إنشاء ملفات ZIP المضغوطة من خلال فتح كائن <code>ZipFile</code> في وضع الكتابة مع تمرير <code>'w'</code> كوسيط ثانٍ، حيث يشبه ذلك فتح ملفٍ نصي في وضع الكتابة من خلال تمرير <code>'w'</code> إلى الدالة <code>open()‎</code>.
</p>

<p>
	إذا مرّرتَ مسارًا إلى التابع ‎<code>write()</code>‎ مع كائن <code>ZipFile</code>، ستضغط شيفرة بايثون الملف الموجود في هذا المسار وتضيفه إلى ملف ZIP. الوسيط الأول للتابع ‎<code>write()</code>‎ هو سلسلة نصية تمثّل اسم الملف المراد إضافته، والوسيط الثاني هو معامل يمثّل نوع عملية الضغط، إذ يخبر هذا النوع الحاسوبَ بالخوارزمية التي يجب أن يستخدمها لضغط الملفات، حيث يمكنك دائمًا ضبط هذه القيمة على <code>zipfile.ZIP_DEFLATED</code> التي تحدّد خوارزمية الضغط Deflate التي تعمل على جميع أنواع البيانات. أدخِل مثلًا ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_36" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> zipfile
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> newZip </span><span class="pun">=</span><span class="pln"> zipfile</span><span class="pun">.</span><span class="typ">ZipFile</span><span class="pun">(</span><span class="str">'new.zip'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'w'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> newZip</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">'spam.txt'</span><span class="pun">,</span><span class="pln"> compress_type</span><span class="pun">=</span><span class="pln">zipfile</span><span class="pun">.</span><span class="pln">ZIP_DEFLATED</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> newZip</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	ستؤدي الشيفرة البرمجية السابقة إلى إنشاء ملف ZIP جديد بالاسم new.zip، حيث يحتوي هذا الملف على محتويات مضغوطة للملف spam.txt.
</p>

<p>
	ضع في بالك أن وضع الكتابة سيؤدي إلى مسح جميع المحتويات الموجودة مسبقًا في ملف ZIP كما هو الحال مع الكتابة في الملفات. إذا أردتَ ببساطة إضافة ملفات إلى ملف ZIP موجود مسبقًا، فمرّر <code>'a'</code> كوسيطٍ ثانٍ إلى الدالة <code>zipfile.ZipFile()‎</code> لفتح ملف ZIP في وضع الإلحاق Append Mode.
</p>

<h2 id="-4">
	تطبيق عملي: إعادة تسمية الملفات ذات تواريخ النمط الأمريكي إلى تواريخ النمط الأوروبي
</h2>

<p>
	لنفترض أن مديرك في العمل يرسل إليك عبر البريد الإلكتروني آلاف الملفات ذات تواريخ النمط الأمريكي (MM-DD-YYYY) الموجودة في أسماء هذه الملفات ويريد إعادة تسميتها إلى تواريخ النمط الأوروبي (DD-MM-YYYY)، إذ قد يستغرق إنجاز هذه المهمة المملة يدويًا وقتًا طويلًا، إذًا لنكتب برنامجًا ينّفذ هذه المهمة نيابةً عنك.
</p>

<p>
	إليك الخطوات التي يفعلها هذا البرنامج:
</p>

<ol>
	<li>
		البحث في جميع أسماء الملفات الموجودة في مجلد العمل الحالي عن التواريخ ذات النمط الأمريكي.
	</li>
	<li>
		إعادة تسمية الملف مع التبديل بين الشهر واليوم لجعله على النمط الأوروبي عند العثور على أحد هذه الملفات.
	</li>
</ol>

<p>
	وبالتالي يجب أن تطبّق شيفرتك البرمجية الخطوات التالية:
</p>

<ol>
	<li>
		إنشاء تعبير نمطي Regex يمكنه تحديد نمط النص للتواريخ ذات النمط الأمريكي.
	</li>
	<li>
		استدعاء التابع ‎<code>os.listdir()</code>‎ للعثور على جميع الملفات الموجودة في مجلد العمل.
	</li>
	<li>
		المرور ضمن حلقة على جميع أسماء الملفات باستخدام التعبير النمطي للتحقق من احتوائه على تاريخ.
	</li>
	<li>
		إذا احتوى اسم الملف على تاريخ، فيجب إعادة تسمية الملف باستخدام الدالة <code>shutil.move()‎</code>.
	</li>
</ol>

<p>
	افتح نافذةً جديدة في محرّرك لإنشاء ملف جديد للمشروع واحفظ شيفرتك البرمجية بالاسم renameDates.py.
</p>

<h3 id="-5">
	الخطوة الأولى: إنشاء تعبير نمطي للتواريخ ذات النمط الأمريكي
</h3>

<p>
	سيحتاج الجزء الأول من البرنامج إلى استيراد الوحدات الضرورية وإنشاء تعبير نمطي يمكنه تحديد تواريخ النمط الأمريكي MM-DD-YYYY. ستذكرك تعليقات <code>TODO</code> في النهاية بما تبقى لتكتبه في هذا البرنامج، حيث كتبناها ليسهل عليك العثور عليها باستخدام ميزة البحث Ctrl-F في محرّر Mu. اجعل شيفرتك البرمجية تبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_38" style=""><span class="pln">   </span><span class="com">#! python3</span><span class="pln">
   </span><span class="com"># renameDates.py - ‫إعادة تسمية أسماء الملفات ذات تنسيق التاريخ الأمريكي MM-DD-YYYY إلى</span><span class="pln">
   </span><span class="com"># ‫تنسيق التاريخ الأوروبي DD-MM-YYYY</span><span class="pln">

</span><span class="pun">➊</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> shutil</span><span class="pun">,</span><span class="pln"> os</span><span class="pun">,</span><span class="pln"> re

   </span><span class="com"># إنشاء تعبير نمطي يطابق الملفات ذات تنسيق التاريخ الأمريكي</span><span class="pln">
</span><span class="pun">➋</span><span class="pln"> datePattern </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">"""^(.*?) # كل النص قبل التاريخ
       ((0|1)?\d)-                     # رقم أو رقمين للشهر
       ((0|1|2|3)?\d)-                 # رقم أو رقمين لليوم
       ((19|20)\d\d)                   # أربعة أرقام للسنة
       (.*?)$                          # كل النص بعد التاريخ
       """</span><span class="pun">,</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">VERBOSE</span><span class="pun">➌)</span><span class="pln">

   </span><span class="com"># TODO: المرور ضمن حلقة على الملفات الموجودة في مجلد العمل</span><span class="pln">

   </span><span class="com"># TODO: تخطي الملفات التي تكون بدون تاريخ</span><span class="pln">

   </span><span class="com"># TODO: الحصول على الأجزاء المختلفة من اسم الملف</span><span class="pln">

   </span><span class="com"># TODO: تشكيل اسم الملف على النمط الأوروبي</span><span class="pln">

   </span><span class="com"># TODO: الحصول على مسارات الملفات الكاملة والمطلقة</span><span class="pln">

   </span><span class="com"># TODO: إعادة تسمية الملفات</span></pre>

<p>
	تعلّمنا في هذا المقال أنه يمكن استخدام الدالة <code>shutil.move()‎</code> لإعادة تسمية الملفات، ووسطاؤها هي اسم الملف المراد إعادة تسميته واسم الملف الجديد، ويجب استيراد الوحدة <code>shutil</code> ➊ بسبب وجود هذه الدالة فيها.
</p>

<p>
	يجب تحديد الملفات التي تريد إعادة تسميتها قبل إعادة تسميتها، إذ يجب إعادة تسمية أسماء الملفات التي لها تواريخ مثل spam4-4-1984.txt و 01‎-03-2014eggs.zip، بينما يمكن تجاهل أسماء الملفات التي لا تحتوي على تواريخ مثل littlebrother.epub.
</p>

<p>
	يمكنك استخدام تعبير نمطي لتحديد هذا النمط، لذا استدعِ التابع <code>re.compile()‎</code> لإنشاء كائن <code>Regex</code> ➋ بعد استيراد الوحدة <code>re</code> في البداية. سيسمح تمرير القيمة <code>re.VERBOSE</code> للوسيط الثاني ➌ بوجود المسافات البيضاء والتعليقات في السلسلة النصية للتعبير النمطي لجعلها أكثر قابلية للقراءة.
</p>

<p>
	تبدأ السلسلة النصية للتعبير النمطي بالمحارف <code>‎^‎(‎.‎*‎?‎)‎</code> لمطابقة أيّ نصٍ موجود في بداية اسم الملف الذي قد يأتي قبل التاريخ. تطابق المجموعة <code>‎((0|1)?\d)‎</code> الشهر، حيث يمكن أن يكون الرقم الأول إما 0 أو 1، وبالتالي يطابق التعبير النمطي القيمةَ <code>12</code> للشهر 12 ويطابق القيمة <code>02</code> للشهر الثاني، حيث يكون هذا الرقم اختياريًا أيضًا بحيث يمكن أن يكون الشهر <code>04</code> أو <code>4</code> للشهر الرابع. مجموعة اليوم هي <code>‎((0|1|2|3)?\d)‎</code> وتتبع منطقًا مشابهًا لمجموعة الشهر، حيث تُعَد القيم <code>3</code> و <code>03</code> و <code>31</code> أرقامًا صالحة للأيام. لاحظ أن هذا التعبير النمطي سيقبل بعض التواريخ غير الصالحة مثل <code>4‎-31-2022</code> و <code>2‎-29-2023</code> و <code>0‎-15-2024</code>، إذ تحتوي التواريخ على الكثير من الحالات الخاصة التي يمكن أن نخطئ بها بسهولة، ولكن يعمل التعبير النمطي في هذا البرنامج جيدًا بما فيه الكفاية للتبسيط.
</p>

<p>
	تُعَد السنة 1885 سنةً صالحة، ولكن يمكنك فقط البحث عن السنوات في القرن العشرين أو الحادي والعشرين، مما سيؤدي إلى منع برنامجك من مطابقة أسماء الملفات التي لها تنسيق مشابه للتاريخ ولكنها لا تمثّل تواريخًا مثل 10‎-10-1000.txt عن طريق الخطأ.
</p>

<p>
	أخيرًا، يتطابق الجزء <code>$(?*.)</code> من التعبير النمطي مع أيّ نص يأتي بعد التاريخ.
</p>

<h3 id="-6">
	الخطوة الثانية: تحديد أجزاء التاريخ من أسماء الملفات
</h3>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_40" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># renameDates.py - ‫إعادة تسمية أسماء الملفات ذات تنسيق التاريخ الأمريكي MM-DD-YYYY إلى</span><span class="pln">
</span><span class="com"># ‫تنسيق التاريخ الأوروبي DD-MM-YYYY</span><span class="pln">

</span><span class="pun">--</span><span class="pln">snip</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"> amerFilename </span><span class="kwd">in</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">listdir</span><span class="pun">(</span><span class="str">'.'</span><span class="pun">):</span><span class="pln">
    mo </span><span class="pun">=</span><span class="pln"> datePattern</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="pln">amerFilename</span><span class="pun">)</span><span class="pln">

    </span><span class="com"># تخطي الملفات التي تكون بدون تاريخ</span><span class="pln">
  </span><span class="pun">➊</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> mo </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">None</span><span class="pun">:</span><span class="pln">
      </span><span class="pun">➋</span><span class="pln"> </span><span class="kwd">continue</span><span class="pln">

  </span><span class="pun">➌</span><span class="pln"> </span><span class="com"># الحصول على الأجزاء المختلفة من اسم الملف</span><span class="pln">
    beforePart </span><span class="pun">=</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">group</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
    monthPart  </span><span class="pun">=</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">group</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
    dayPart    </span><span class="pun">=</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">group</span><span class="pun">(</span><span class="lit">4</span><span class="pun">)</span><span class="pln">
    yearPart   </span><span class="pun">=</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">group</span><span class="pun">(</span><span class="lit">6</span><span class="pun">)</span><span class="pln">
    afterPart  </span><span class="pun">=</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">group</span><span class="pun">(</span><span class="lit">8</span><span class="pun">)</span><span class="pln">

</span><span class="pun">--</span><span class="pln">snip</span><span class="pun">–</span></pre>

<p>
	إذا كانت قيمة كائن <code>Match</code> الذي يعيده التابع <code>search()‎</code> هي <code>None</code> ➊، فلن يتطابق اسم الملف الموجود في المتغير <code>amerFilename</code> مع التعبير النمطي، وستتخطى تعليمة <code>continue</code> ➋ بقية الحلقة وتنتقل إلى اسم الملف التالي، وإلّا فستُخزَّن السلاسل النصية المختلفة المطابِقة مع مجموعات التعبير النمطي في متغيرات بالاسم <code>beforePart</code> و <code>monthPart</code> و <code>dayPart</code> و <code>yearPart</code> و <code>afterPart</code> ➌. ستُستخدَم السلاسل النصية الموجودة في هذه المتغيرات لتشكيل اسم الملف على النمط الأوروبي في الخطوة التالية.
</p>

<p>
	أبقِ أرقام المجموعة سهلة الاستخدام من خلال محاولة قراءة التعبير النمطي من البداية وحساب كل مرة يظهر فيها قوس مفتوح. اكتب مخططًا تفصيليًا <a href="https://academy.hsoub.com/programming/python/%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-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2345/" rel="">للتعبير النمطي</a> دون التفكير في الشيفرة البرمجية، حيث يمكن أن يساعدك المثال التالي في تصوّر هذه المجموعات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_42" style=""><span class="pln">datePattern </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">"""^(1) # كل النص قبل التاريخ
    (2 (3) )-                     # رقم أو رقمين للشهر
    (4 (5) )-                     # رقم أو رقمين لليوم
    (6 (7) )                      # أربعة أرقام للسنة
    (8)$                          # كل النص بعد التاريخ
    """</span><span class="pun">,</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">VERBOSE</span><span class="pun">)</span></pre>

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

<h3 id="-7">
	الخطوة الثالثة: تشكيل اسم الملف الجديد وإعادة تسمية الملفات
</h3>

<p>
	جرّب سَلسَلة السلاسل النصية الموجودة في المتغيرات من الخطوة السابقة مع التاريخ ذي النمط الأوروبي، حيث يأتي اليوم قبل الشهر. املأ المهام <code>TODO</code> الثلاثة المتبقية في برنامجك بالشيفرة البرمجية التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_44" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># renameDates.py - ‫إعادة تسمية أسماء الملفات ذات تنسيق التاريخ الأمريكي MM-DD-YYYY إلى</span><span class="pln">
</span><span class="com"># ‫تنسيق التاريخ الأوروبي DD-MM-YYYY</span><span class="pln">

</span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">

     </span><span class="com"># تشكيل اسم الملف على النمط الأوروبي</span><span class="pln">
  </span><span class="pun">➊</span><span class="pln"> euroFilename </span><span class="pun">=</span><span class="pln"> beforePart </span><span class="pun">+</span><span class="pln"> dayPart </span><span class="pun">+</span><span class="pln"> </span><span class="str">'-'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> monthPart </span><span class="pun">+</span><span class="pln"> </span><span class="str">'-'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> yearPart </span><span class="pun">+</span><span class="pln">
                    afterPart

     </span><span class="com"># الحصول على مسارات الملفات الكاملة والمطلقة</span><span class="pln">
     absWorkingDir </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">abspath</span><span class="pun">(</span><span class="str">'.'</span><span class="pun">)</span><span class="pln">
     amerFilename </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">absWorkingDir</span><span class="pun">,</span><span class="pln"> amerFilename</span><span class="pun">)</span><span class="pln">
     euroFilename </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">absWorkingDir</span><span class="pun">,</span><span class="pln"> euroFilename</span><span class="pun">)</span><span class="pln">

     </span><span class="com"># إعادة تسمية الملفات</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">f</span><span class="str">'Renaming "{amerFilename}" to "{euroFilename}"...'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">➌</span><span class="pln"> </span><span class="com">#shutil.move(amerFilename, euroFilename)   # ألغِ التعليق بعد الاختبار</span></pre>

<p>
	خزّن السلسلة النصية المتسلسلة في متغير بالاسم <code>euroFilename</code> ➊، ثم مرّر اسم الملف الأصلي الموجود في المتغير <code>amerFilename</code> والمتغير <code>euroFilename</code> الجديد إلى الدالة <code>shutil.move()‎</code> لإعادة تسمية الملف ➌.
</p>

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

<h3 id="-8">
	أفكار لبرامج مماثلة
</h3>

<p>
	هناك العديد من الأسباب الأخرى التي قد تجعلك ترغب في إعادة تسمية عدد كبير من الملفات مثل:
</p>

<ul>
	<li>
		إضافة بادئة إلى بداية اسم الملف مثل إضافة <code>spam_‎</code> لإعادة تسمية الملف eggs.txt إلى الاسم spam_eggs.txt.
	</li>
	<li>
		تغيير أسماء الملفات التي تحتوي على تواريخ ذات نمط أوروبي إلى تواريخ ذات نمط الأمريكي.
	</li>
	<li>
		حذف الأصفار من أسماء الملفات مثل spam0042.txt.
	</li>
</ul>

<h2 id="zip-3">
	تطبيق عملي: إنشاء نسخة احتياطية لمجلد في ملف مضغوط ZIP
</h2>

<p>
	لنفترض أنك تعمل على مشروع تحتفظ بملفاته في مجلد بالاسم <code>C:\AlsPythonBook</code>، ولا بد أنك قلق بشأن فقدان عملك، لذا سترغب في إنشاء "لقطات" من ملفات ZIP للمجلد بأكمله، إذ قد ترغب في الاحتفاظ بنسخ مختلفة، لذلك يجب أن يزيد اسم ملف ZIP في كل مرة تنشئ فيها نسخة مثل AlsPythonBook_1.zip و AlsPythonBook_2.zip و AlsPythonBook_3.zip وإلخ. يمكنك إنجاز ذلك يدويًا، ولكنه أمر مزعج إلى حدٍ ما، وقد تخطئ في ترقيم أسماء ملفات ZIP، فمن الأسهل تشغيل برنامج ينجز هذه المهمة المملة نيابةً عنك.
</p>

<p>
	افتح نافذة جديدة في محرّرك لإنشاء ملف جديد لهذا المشروع واحفظه بالاسم backupToZip.py.
</p>

<h3 id="zip-4">
	الخطوة الأولى: اكتشاف اسم الملف المضغوط ZIP
</h3>

<p>
	سنضع الشيفرة البرمجية الخاصة بهذا البرنامج في دالة اسمها <code>backupToZip()‎</code>، حيث سيؤدي ذلك إلى تسهيل نسخ الدالة ولصقها في برامج بايثون الأخرى التي تحتاج إليها. ستُستدعَى هذه الدالة لإجراء النسخ الاحتياطي في نهاية البرنامج، لذا اجعل برنامجك يبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_46" style=""><span class="pln">   </span><span class="com">#! python3</span><span class="pln">
   </span><span class="com"># backupToZip.py - ‫نسخ مجلد كامل ومحتوياته في ملف ZIP يزيد اسمه بمقدار واحد في كل مرة يُنسَخ فيها</span><span class="pln">

</span><span class="pun">➊</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> zipfile</span><span class="pun">,</span><span class="pln"> os

   </span><span class="kwd">def</span><span class="pln"> backupToZip</span><span class="pun">(</span><span class="pln">folder</span><span class="pun">):</span><span class="pln">
       </span><span class="com"># إنشاء نسخة احتياطية من محتويات المجلد بالكامل في ملف‫ ZIP</span><span class="pln">

       folder </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">abspath</span><span class="pun">(</span><span class="pln">folder</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="pun">➋</span><span class="pln"> number </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </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">
           zipFilename </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">basename</span><span class="pun">(</span><span class="pln">folder</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'_'</span><span class="pln"> </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"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'.zip'</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> </span><span class="kwd">not</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">zipFilename</span><span class="pun">):</span><span class="pln">
               </span><span class="kwd">break</span><span class="pln">
           number </span><span class="pun">=</span><span class="pln"> number </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">

    </span><span class="pun">➍</span><span class="pln"> </span><span class="com"># TODO: إنشاء ملف مضغوط‫ ZIP</span><span class="pln">

       </span><span class="com"># TODO: المرور على شجرة المجلدات بأكملها وضغط الملفات الموجودة في كل مجلد</span><span class="pln">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Done.'</span><span class="pun">)</span><span class="pln">

backupToZip</span><span class="pun">(</span><span class="str">'C:\\delicious'</span><span class="pun">)</span></pre>

<p>
	أضِف أولًا سطر Shebang (الذي يبدأ بالسلسلة النصية <code>!#</code>) مع وصف ما يفعله البرنامج، ثم استورد وحدات <code>zipfile</code> و <code>os</code> ➊. عرّف بعد ذلك دالة بالاسم <code>backupToZip()‎</code>، حيث تأخذ هذه الدالة معاملًا واحدًا فقط هو <code>folder</code>، والذي هو سلسلة نصية تمثّل مسارًا إلى المجلد الذي يجب نسخ محتوياته احتياطيًا. ستحدّد هذه الدالة اسم الملف المُستخدَم لملف ZIP الذي ستنشئه، ثم تنشئ هذه الدالة الملف، وتمر على المجلد <code>folder</code>، وتضيف كلًا من المجلدات الفرعية والملفات إلى ملف ZIP. اكتب تعليقات <code>TODO</code> لهذه الخطوات في الشيفرة البرمجية لتذكير نفسك بإنجازها لاحقًا ➍.
</p>

<p>
	يستخدم الجزء الأول -الذي يمثّل تسمية الملف ZIP- الاسم الأساسي للمسار المطلق للمجلد <code>folder</code>. إذا كان المجلد الذي ننسخه احتياطيًا هو <code>C:\delicious</code>، فيجب أن يكون اسم الملف ZIP هو delicious_N.zip، حيث <code>N = 1</code> هي المرة الأولى التي نشغّل فيها البرنامج و <code>N = 2</code> هي المرة الثانية وإلخ.
</p>

<p>
	يمكنك تحديد ما يجب أن تكون عليه قيمة <code>N</code> من خلال التحقق مما إذا كان الملف delicious<em>1.zip موجودًا مسبقًا، ثم التحقق مما إذا كان الملف delicious</em>2.zip موجودًا مسبقًا وإلخ. استخدم متغيرًا اسمه <code>number</code> لتمثيل N ➋، واستمر في زيادته ضمن الحلقة التي تستدعي التابع <code>os.path.exists()‎</code> للتحقق من وجود الملف ➌. سيؤدي العثور على أول اسم ملف غير موجود إلى كسر الحلقة باستخدام التعليمة <code>break</code>، لأنها عثرت على اسم الملف المضغوط الجديد.
</p>

<h3 id="zip-5">
	الخطوة الثانية: إنشاء ملف مضغوط ZIP جديد
</h3>

<p>
	لننشئ الآن ملف ZIP، لذا اجعل برنامجك يبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_48" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># backupToZip.py - نسخ مجلد كامل ومحتوياته في ملف‫ ZIP يزيد اسمه بمقدار واحد في كل مرة يُنسَخ فيها</span><span class="pln">

</span><span class="pun">--</span><span class="pln">snip</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">
        zipFilename </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">basename</span><span class="pun">(</span><span class="pln">folder</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'_'</span><span class="pln"> </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"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'.zip'</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="kwd">not</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">zipFilename</span><span class="pun">):</span><span class="pln">
            </span><span class="kwd">break</span><span class="pln">
        number </span><span class="pun">=</span><span class="pln"> number </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">

    </span><span class="com"># إنشاء ملف مضغوط‫ ZIP</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">f</span><span class="str">'Creating {zipFilename}...'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">➊</span><span class="pln"> backupZip </span><span class="pun">=</span><span class="pln"> zipfile</span><span class="pun">.</span><span class="typ">ZipFile</span><span class="pun">(</span><span class="pln">zipFilename</span><span class="pun">,</span><span class="pln"> </span><span class="str">'w'</span><span class="pun">)</span><span class="pln">

     </span><span class="com"># TODO: المرور على شجرة المجلدات بأكملها وضغط الملفات الموجودة في كل مجلد</span><span class="pln">
     </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Done.'</span><span class="pun">)</span><span class="pln">

backupToZip</span><span class="pun">(</span><span class="str">'C:\\delicious'</span><span class="pun">)</span></pre>

<p>
	خزّنا اسم ملف ZIP الجديد في المتغير <code>zipFilename</code>، ويمكننا الآن استدعاء الدالة <code>zipfile.ZipFile()‎</code> لإنشاء ملف ZIP فعليًا ➊. تأكد من تمرير <code>'w'</code> كوسيطٍ ثانٍ لهذه الدالة لفتح الملف ZIP في وضع الكتابة.
</p>

<h3 id="zip-6">
	الخطوة الثالثة: المرور على شجرة المجلدات والإضافة إلى الملف المضغوط ZIP
</h3>

<p>
	يجب الآن أن تستخدم الدالة <code>os.walk()‎</code> لسرد كل ملف موجود في المجلد ومجلداته الفرعية، لذا اجعل برنامجك يبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5539_50" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># backupToZip.py -  نسخ مجلد كامل ومحتوياته في ملف‫ ZIP يزيد اسمه بمقدار واحد في كل مرة يُنسَخ فيها</span><span class="pln">

</span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">

     </span><span class="com"># المرور على شجرة المجلدات بأكملها وضغط الملفات الموجودة في كل مجلد</span><span class="pln">
  </span><span class="pun">➊</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> foldername</span><span class="pun">,</span><span class="pln"> subfolders</span><span class="pun">,</span><span class="pln"> filenames </span><span class="kwd">in</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">walk</span><span class="pun">(</span><span class="pln">folder</span><span class="pun">):</span><span class="pln">
         </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">f</span><span class="str">'Adding files in {foldername}...'</span><span class="pun">)</span><span class="pln">
         </span><span class="com"># ‫إضافة المجلد الحالي إلى ملف ZIP</span><span class="pln">
      </span><span class="pun">➋</span><span class="pln"> backupZip</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">foldername</span><span class="pun">)</span><span class="pln">

         </span><span class="com"># إضافة كافة الملفات الموجودة في هذا المجلد إلى ملف‫ ZIP</span><span class="pln">
      </span><span class="pun">➌</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> filename </span><span class="kwd">in</span><span class="pln"> filenames</span><span class="pun">:</span><span class="pln">
            newBase </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">basename</span><span class="pun">(</span><span class="pln">folder</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'_'</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> filename</span><span class="pun">.</span><span class="pln">startswith</span><span class="pun">(</span><span class="pln">newBase</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> filename</span><span class="pun">.</span><span class="pln">endswith</span><span class="pun">(</span><span class="str">'.zip'</span><span class="pun">):</span><span class="pln">
                </span><span class="kwd">continue</span><span class="pln">   </span><span class="com"># ‫لا تنشئ نسخة احتياطية من ملفات ZIP الاحتياطية</span><span class="pln">
             backupZip</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">foldername</span><span class="pun">,</span><span class="pln"> filename</span><span class="pun">))</span><span class="pln">
     backupZip</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="str">'Done.'</span><span class="pun">)</span><span class="pln">

backupToZip</span><span class="pun">(</span><span class="str">'C:\\delicious'</span><span class="pun">)</span></pre>

<p>
	يمكنك استخدام الدالة <code>os.walk()‎</code> في حلقة <code>for</code> ➊، حيث ستعيد في كل تكرار اسم المجلد الحالي لهذا التكرار والمجلدات الفرعية الموجودة في هذا المجلد وأسماء الملفات الموجودة في هذا المجلد. يُضاف المجلد إلى ملف ZIP ➋ في حلقة <code>for</code>، ويمكن لحلقة <code>for</code> المتداخلة المرور على كل اسم ملف في القائمة <code>filenames</code> ➌، ويُضاف كل منها إلى ملف ZIP باستثناء ملفات ZIP الاحتياطية التي أنشأناها مسبقًا.
</p>

<p>
	سينتج ما يلي عند تشغيل هذا البرنامج:
</p>

<pre class="ipsCode">Creating delicious_1.zip...
Adding files in C:\delicious...
Adding files in C:\delicious\cats...
Adding files in C:\delicious\waffles...
Adding files in C:\delicious\walnut...
Adding files in C:\delicious\walnut\waffles...
Done.
</pre>

<p>
	سيضع هذا البرنامج جميع الملفات الموجودة في المجلد <code>C:\delicious</code> في ملف ZIP بالاسم delicious_2.zip في المرة الثانية لتشغيله وهكذا.
</p>

<h3 id="-9">
	أفكار لبرامج مماثلة
</h3>

<p>
	يمكنك الاستفادة من فكرة المرور على شجرة المجلدات وإضافة الملفات إلى ملفات الأرشفة ZIP المضغوطة في العديد من البرامج الأخرى، فمثلًا يمكنك كتابة البرامج التي تنجز المهام التالية:
</p>

<ul>
	<li>
		المرور على شجرة المجلدات وأرشفة الملفات التي لها امتدادات محددة فقط مثل <code>‎.txt</code> أو <code>‎.py</code>.
	</li>
	<li>
		المرور على شجرة المجلدات وأرشفة جميع الملفات باستثناء ملفات <code>‎.txt</code> و <code>‎.py</code>.
	</li>
	<li>
		البحث عن المجلد في شجرة المجلدات الذي يحتوي على أكبر عدد من الملفات أو المجلد الذي يستخدم أكبر مساحة على القرص الصلب.
	</li>
</ul>

<h2 id="-11">
	مشاريع للتدريب
</h2>

<p>
	حاول كتابة البرامج التي تؤدي المهام التي سنوضّحها فيما يلي لكسب خبرة عملية أكبر.
</p>

<h3 id="-12">
	برنامج لإنشاء نسخة انتقائية للملفات من شجرة المجلدات
</h3>

<p>
	اكتب برنامجًا يمر على شجرة المجلدات ويبحث عن الملفات التي لها امتداد ملف محدّد (مثل ‎<code>.pdf</code>‎ أو ‎<code>.jpg</code>‎)، وانسخ هذه الملفات من أيّ موقع توجد فيه في مجلد جديد.
</p>

<h3 id="-13">
	برنامج لحذف الملفات غير الضرورية
</h3>

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

<p>
	اكتب برنامجًا يمر على شجرة المجلدات ويبحث عن الملفات أو المجلدات الكبيرة استثنائيًا مثل الملفات أو المجلدات التي يزيد حجم ملفها عن 100 ميجابايت، حيث يمكنك استخدام الدالة <code>os.path.getsize()‎</code> من وحدة <code>os</code> للحصول على حجم الملف. اطبع هذه الملفات مع مسارها المطلق على الشاشة.
</p>

<h3 id="-14">
	ملء الفجوات في ترقيم أسماء الملفات
</h3>

<p>
	اكتب برنامجًا يبحث عن جميع الملفات ذات البادئة المُحدَّدة -مثل spam001.txt و spam002.txt وإلخ- في مجلدٍ واحد، ويحدّد هذا البرنامج موقع أيّ فجوات في الترقيم مثل وجود الملفين spam001.txt و spam003.txt دون وجود الملف spam002.txt، لذا اجعل البرنامج يعيد تسمية جميع الملفات اللاحقة لسد هذه الفجوة. اكتب أيضًا برنامجًا آخر يمكنه إدراج فجوات في الملفات المرقّمة بحيث يمكن إضافة ملف جديد.
</p>

<h2 id="-15">
	الخلاصة
</h2>

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

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

<p>
	يجب في أغلب الأحيان تنفيذ هذه العمليات على الملفات الموجودة في أحد المجلدات وعلى كل مجلد موجود في هذا المجلد وعلى كل مجلد موجود في تلك المجلدات وإلخ. تتولى الدالة <code>os.walk()‎</code> هذه الرحلة عبر المجلدات نيابةً عنك حتى تتمكّن من التركيز على ما يحتاج برنامجك إلى فعله مع الملفات الموجودة في هذه المجلدات.
</p>

<p>
	تمنحك وحدة <code>zipfile</code> طريقةً لضغط وفك ضغط الملفات في أرشيفات <code>‎.ZIP</code> باستخدام لغة بايثون. تسهّل الوحدة <code>zipfile</code> -مع دوال معالجة الملفات الخاصة بوحدتي <code>os</code> و <code>shutil</code>- تجميعَ العديد من الملفات من أيّ مكان على قرص حاسوبك الصلب. يُعَد رفع هذه الملفات المضغوطة ZIP على مواقع الويب أو إرسالها بوصفها مرفقات في البريد الإلكتروني أسهلَ بكثير من العديد من الملفات المنفصلة.
</p>

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

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://automatetheboringstuff.com/2e/chapter10/" rel="external nofollow">Organizing Files</a> لصاحبه Al Sweigart.
</p>

<h2 id="-16">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/python/%D9%82%D8%B1%D8%A7%D8%A1%D8%A9-%D9%88%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%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-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2347/" rel="">قراءة وكتابة الملفات باستخدام لغة بايثون python</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%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%88%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1858/" rel="">التعامل مع الملفات والمسارات في بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%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%85%D9%84%D9%81%D8%A7%D8%AA-%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-r484/" rel="">كيفية التعامل مع الملفات النصية في بايثون 3</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D9%85%D8%B4%D8%A7%D8%B1%D9%8A%D8%B9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D9%86%D8%A7%D8%B3%D8%A8-%D8%A7%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86-r2185/" rel="">مشاريع بايثون عملية تناسب المبتدئين</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2358</guid><pubDate>Thu, 04 Jul 2024 15:00:00 +0000</pubDate></item><item><title>&#x642;&#x631;&#x627;&#x621;&#x629; &#x648;&#x643;&#x62A;&#x627;&#x628;&#x629; &#x627;&#x644;&#x645;&#x644;&#x641;&#x627;&#x62A; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x644;&#x63A;&#x629; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646; Python</title><link>https://academy.hsoub.com/programming/python/%D9%82%D8%B1%D8%A7%D8%A1%D8%A9-%D9%88%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%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-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2347/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_06/----(1).png.a9580bf018bafd77bbf8c4b8ff120eab.png" /></p>
<p>
	يمكننا تخزين المعلومات في المتغيرات في برنامجنا وستبقى موجودة طالما استمر تشغيل البرنامج، لكنا ماذا لو أردنا الحفاظ على البيانات بعد انتهاء تنفيذ البرنامج؟ سنحتاج إلى حفظها إلى ملف؛ وسنتعلم في هذا المقال كيفية استخدام بايثون لإنشاء وقراءة وكتابة الملفات في حاسوبنا.
</p>

<h2 id="">
	الملفات ومساراتها
</h2>

<p>
	يملك كل ملف خاصيتان أساسيتان: اسم الملف ومساره. يحدد مسار الملف أين سيظهر في حاسوبك، فمثلًا هنالك ملف في حاسوبي الذي يعمل بنظام ويندوز موجود اسمه <code>project.docx</code> في المسار <code>C:\Users\Al\Documents</code>.
</p>

<p>
	الجزء الذي يلي اسم الملف ويأتي بعد النقطة يسمى بامتداد الملف <code>file extension</code> ويخبرنا ما هو نوع الملف، فمثلًا الملف <code>project.docx</code> هو مستند وورد؛ بينما تشير Users و Al و Documents إلى مجلدات.
</p>

<p>
	يمكن أن تحتوي المجلدات على ملفات ومجلدات أخرى، فمثلًا الملف <code>project.docx</code> موجود في المجلد Documents الذي بدوره موجود في المجلد Al الموجود في المجلد <code>Users</code>. يوضح الشكل الآتي هذه البنية.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150977" href="https://academy.hsoub.com/uploads/monthly_2024_06/000009.jpg.2039569e3a2a7c91f7078743e0987a7e.jpg" rel=""><img alt="000009" class="ipsImage ipsImage_thumbnailed" data-fileid="150977" data-unique="827e5k691" src="https://academy.hsoub.com/uploads/monthly_2024_06/000009.jpg.2039569e3a2a7c91f7078743e0987a7e.jpg"> </a>
</p>

<p style="text-align: center;">
	الشكل 1: ملف موجود في مجلد
</p>

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

<p>
	تظهر أجهزة التخزين الأخرى مثل أقراص DVD أو وسائط تخزين USB بطرائق مختلف حسب نظام التشغيل، ففي ويندوز ستظهر على شكل قرص جديد له حرف مختلف مثل <code>D:/‎</code> أو E:/<code>‎</code>. بينما في ماك فستظهر كمجلد جديد في المجلد <code>/Volumes</code>، وفي لينكس ستظهر كمجلدات جديدة في المجلد <code>‎</code>/mnt (أو <code>‎/media</code> حسب التوزيعة عندك).
</p>

<p>
	من المهم أن تلاحظ أن أسماء الملفات والمجلدات غير حساسة لحالة الأحرف في ويندوز وماك، لكنها حساسة لحالة الأحرف في لينكس.
</p>

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

<h3 id="-1">
	الخط المائل الخلفي \ في ويندوز والخط المائل الأمامي / في ماك ولينكس
</h3>

<p>
	تستعمل مسارات الملفات في أنظمة ويندوز الخط المائل الخلفي <code>\</code> الذي يفصل بين أسماء المجلدات؛ أما في ماك ولينكس فيستعمل الخط المائل الأمامي <code>/</code> فاصلًا بين المجلدات؛ ولو أردت أن تعمل برامجك التي تكتبها على جميع الأنظمة (وهذا أمر مهم أنصحك به) فعليك أن تتعامل مع كلا الحالتين.
</p>

<p>
	لحسن الحظ هنالك دالة في الوحدة <code>pathlib</code> باسم Path()<code>‎</code>، التي نمرر إليها سلاسل نصية بأسماء المجلدات والملف المطلوب، وستعيد الدالة <code>Path()‎</code> سلسلةً نصيةً لمسار الملف يستعمل الفاصل الصحيح بين المجلدات وفقًا لنظام التشغيل:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_8" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> pathlib </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Path</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'spam'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'olive'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'eggs'</span><span class="pun">)</span><span class="pln">

</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'spam/olive/eggs'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> str</span><span class="pun">(</span><span class="typ">Path</span><span class="pun">(</span><span class="str">'spam'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'olive'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'eggs'</span><span class="pun">))</span><span class="pln">
</span><span class="str">'spam\\olive\\eggs'</span></pre>

<p>
	لاحظ أن من الشائع حين استيراد <code>pathlib</code> أن نكتب <code>from pathlib import Path</code> وإلا فسنحتاج إلى كتابة <code>pathlib.Path</code> في كل مرة نريد استعمال <code>Path</code> فيها.
</p>

<p>
	سأشغل أمثلة هذا المقال على نظام ويندوز، لذا ستعيد الدالة <code>Path('spam', 'olive', 'eggs')‎</code> الكائن <code>WindowsPath</code> للمسار النهائي <code>WindowsPath('spam/olive/eggs')‎</code>؛ وصحيحٌ أن ويندوز يستعمل الخط المائل الخلفي في المسارات، لكن تمثيل الكائن <code>WindowsPath</code> في الطرفية التفاعلية يستعمل الخط المائل الأمامي، هذا لأن مطوري البرمجيات مفتوحة المصدر يفضلون نظام لينكس ويستعملون العادات الخاصة به أثناء التطوير.
</p>

<p>
	إذا أردنا الحصول على سلسلة نصية من المسار، فيمكننا تمرير الكائن <code>WindowsPath</code> إلى الدالة str()<code>‎</code> التي ستعيد في مثالنا السلسلة النصية <code>'spam\\olive\\eggs'</code>، لاحظ أن الخطوط المائلة الخلفية مضاعفة لأن كل خط مائل خلفي يحتاج إلى خطٍ مائل خلفي آخر لتهريبه.
</p>

<p>
	إذا استخدمنا الدالة السابقة في نظام لينكس فستعيد كائن <code>PosixPath</code>، الذي حين تمريره إلى الدالة str()<code>‎</code> فسيعيد السلسلة النصية <code>'spam/olive/eggs'</code> (كلمة <code>POSIX</code> تشير إلى مجموعة من المعايير الحاكمة للأنظمة الشبيهة بيونكس <code>Unix-like</code> مثل لينكس، إذا لم تجرب لينكس من قبل فأنصحك وبشدة أن تجربه).
</p>

<p>
	يمكن تمرير كائنات <code>Path</code> (سواءً كانت <code>WindowsPath</code> أو <code>PosixPath</code> اعتمادًا على نظام تشغيلك) إلى دوال أخرى متعلقة بالتعامل مع الملفات والتي سنشرحها خلال هذا المقال.
</p>

<p>
	المثال الآتي يولد مجموعة من مسارات الملفات في أحد المجلدات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_10" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> pathlib </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Path</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> myFiles </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'accounts.txt'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'details.csv'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'invite.docx'</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"> filename </span><span class="kwd">in</span><span class="pln"> myFiles</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="typ">Path</span><span class="pun">(</span><span class="pln">r</span><span class="str">'C:\Users\Al'</span><span class="pun">,</span><span class="pln"> filename</span><span class="pun">))</span><span class="pln">
C</span><span class="pun">:</span><span class="pln">\Users\Al\accounts</span><span class="pun">.</span><span class="pln">txt
C</span><span class="pun">:</span><span class="pln">\Users\Al\details</span><span class="pun">.</span><span class="pln">csv
C</span><span class="pun">:</span><span class="pln">\Users\Al\invite</span><span class="pun">.</span><span class="pln">docx</span></pre>

<p>
	يفصل الخط المائل الخلفي بين المجلدات في ويندوز، لذا لا يمكنك استخدامه في أسماء الملفات، لكنك تستطيع استخدام الخطوط المائلة الخلفية <code>\</code> في ماك ولينكس، فبينما يشير المسار <code>Path(r'spam\eggs')‎</code> إلى مجلدين مختلفين (أو الملف <code>eggs</code> في المجلد <code>spam</code>) في ويندوز، لكنه يشير إلى مجلد أو ملف باسم <code>spam\eggs</code> في ماك ولينكس. لهذا السبب من المستحسن استخدام الخطوط المائلة الأمامية <code>/</code> في شيفرات بايثون دومًا، وسنفعل المثل في أمثلة المقال، وستضمن لنا الوحدة <code>pathlib</code> أن المسارات التي نستخدمها تعمل على جميع أنظمة التشغيل.
</p>

<p>
	لاحظ أن الوحدة <code>pathlib</code> جديدة في بايثون 3.4 وأتت لتستبدل دوال <code>os.path</code> القديمة؛ وتدعمها دوال المكتبة القياسية في بايثون بدءًا من الإصدار 3.6. إذا كنت تعمل مع سكربتات مكتوبة بإصدار بايثون 2 فأنصحك أن تستعمل الوحدة <code>pathlib2</code> التي توفر إمكانية <code>pathlib</code> في بايثون 2.7. يشرح المقال 1 خطوات تثبيت <code>pathlib2</code> باستخدام <code>pip</code>.
</p>

<p>
	سأوضح أي اختلافات واستخدامات للوحدة os حين الحاجة، فقد تستفيد منها حين قراءة السكربتات القديمة أو التي كتبها غيرك.
</p>

<h3 id="-2">
	استخدام العامل / لجمع المسارات
</h3>

<p>
	نستخدم العامل <code>+</code> عادةً لجمع عددين كما في التعبير 2 + 2، الذي ينتج القيمة العددية 4، لكن يمكننا أيضًا استخدام العامل <code>+</code> لجمع سلسلتين نصيتين كما في التعبير <code>'Hello' + 'World'</code> الذي ينتج السلسلة النصية 'HelloWorld'. وبشكل مشابه يستعمل العامل <code>/</code> للقسمة لكن يمكنه أيضًا أن يجمع بين كائنات <code>Path</code> والسلاسل النصية، وهو يفيد في التعامل مع كائنات <code>Path</code> التي أنشأناها سابقًا عبر الدالة Path()<code>‎</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_12" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> pathlib </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Path</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'spam'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="str">'olive'</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="str">'eggs'</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'spam/olive/eggs'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'spam'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'olive/eggs'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'spam/olive/eggs'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'spam'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'olive'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'eggs'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'spam/olive/eggs'</span><span class="pun">)</span></pre>

<p>
	يسهل استخدام العامل <code>/</code> مع كائنات <code>Path</code> عملية جمع المسارات مع بعضها كما لو كانت سلاسل نصية بسيطة، واستخدامه أكثر أمانًا من إجراء عملية جمع للسلاسل النصية يدويًا أو عبر التابع join()<code>‎</code> كما في المثال الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_14" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> homeFolder </span><span class="pun">=</span><span class="pln"> r</span><span class="str">'C:\Users\Al'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> subFolder </span><span class="pun">=</span><span class="pln"> </span><span class="str">'spam'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> homeFolder </span><span class="pun">+</span><span class="pln"> </span><span class="str">'\\'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> subFolder
</span><span class="str">'C:\\Users\\Al\\spam'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</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">homeFolder</span><span class="pun">,</span><span class="pln"> subFolder</span><span class="pun">])</span><span class="pln">
</span><span class="str">'C:\\Users\\Al\\spam'</span></pre>

<p>
	الشيفرة السابقة ليست آمنة لأن الخطوط المائلة الخلفية لا تعمل إلا على ويندوز كما ناقشنا في الأقسام السابقة. يمكنك أن تضيف عبارةً شرطيةً <code>if</code> للتحقق من <code>sys.platform</code> (الذي يحتوي على سلسلة نصية تصف نظام التشغيل المستعمل) لتحديد ما هو نوع الخط المائل الذي نريد استخدامه. لكن استخدام هذه الشيفرة في كل مكان تريد التعامل مع مسارات الملفات فيه هو أمر متعب وغير متناسق ومن المرجح أن يسبب علل برمجية.
</p>

<p>
	تحل الوحدة <code>pathlib</code> هذه المشاكل بإعادة استخدام معامل القسمة / ليجمع بين المسارات دون مشاكل بغض النظر عن نظام التشغيل المستعمل. يوضح المثال الآتي آلية استخدامه:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_16" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> homeFolder </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'C:/Users/Al'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> subFolder </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'spam'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> homeFolder </span><span class="pun">/</span><span class="pln"> subFolder
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/spam'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">homeFolder </span><span class="pun">/</span><span class="pln"> subFolder</span><span class="pun">)</span><span class="pln">
</span><span class="str">'C:\\Users\\Al\\spam'</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_18" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'spam'</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="str">'olive'</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="str">'eggs'</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;stdin&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">TypeError</span><span class="pun">:</span><span class="pln"> unsupported operand type</span><span class="pun">(</span><span class="pln">s</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"> </span><span class="str">'str'</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="str">'str'</span></pre>

<p>
	تقيّم بايثون التعبير البرمجي الذي يستعمل العامل / من اليسار إلى اليمين إلى كائن <code>Path</code>، لهذا يجب أن يكون أول أو ثاني قيمة من اليسار من النوع <code>Path</code> لكي تستطيع إنتاج كائن <code>Path</code> من التعبير البرمجي. هذه هي آلية العمل التي تتبعها بايثون للحصول على كائن <code>Path</code> النهائي:
</p>

<p style="text-align: center;">
	<img alt="000091.png" class="ipsImage ipsImage_thumbnailed" data-fileid="150982" data-ratio="59.40" data-unique="91bf9j5b4" width="298" src="https://academy.hsoub.com/uploads/monthly_2024_06/000091.png.d54d165a864d4319193d086c701d05cb.png">
</p>

<p style="text-align: center;">
	الشكل 2: آلية تفسير المسارات مع العامل <code>/</code>
</p>

<p>
	إذا ظهرت رسالة الخطأ TypeError: unsupported operand type(s) for /: 'str' and 'str'‎ فهذا يعني أن علينا وضع الكائن <code>Path</code> في الطرف الأيسر من التعبير البرمجي.
</p>

<p>
	يستبدل العامل <code>/</code> الدالةَ <code>os.path.join()‎</code> التي يمكنك معرفة المزيد عنها من التوثيق الرسمي <a href="https://docs.python.org/3/library/os.path.html#os.path.join." ipsnoembed="false" rel="external nofollow">https://docs.python.org/3/library/os.path.html#os.path.join.</a>
</p>

<h3 id="-3">
	مجلد العمل الحالي
</h3>

<p>
	يملك كل برنامج تشغله على حاسوب ما يسمى «مجلد العمل الحالي» current working directory أو اختصارًا cwd؛ تفترض بايثون أن أي ملفات أو مسارات لا تبدأ بالمجلد الجذر هي موجودة في مجلد العمل الحالي.
</p>

<p>
	<strong>ملاحظة</strong>: صحيح أننا نقول «مجلد» ترجمةً لكلمة directory التي تعني «موجِّه»، لكنها شائعة بين المستخدمين العرب أكثر؛ ولا أحد يقول current working folder. أغلبية الاصطلاحات البرمجية تستعمل directory بدلًا من folder، لذا ستجد هذه الكلمة مستعملةً في أسماء الدوال المشروحة تاليًا.
</p>

<p>
	يمكننا الحصول على سلسلة نصية تمثل مجلد العمل الحالي باستخدام <code>Path.cwd()‎</code>، ويمكن تغييرها باستخدام <code>os.chdir()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_20" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> pathlib </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Path</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> os
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">cwd</span><span class="pun">()</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/AppData/Local/Programs/Python/Python37'</span><span class="pun">)</span><span class="str">'
&gt;&gt;&gt; os.chdir('</span><span class="pln">C</span><span class="pun">:</span><span class="pln">\\</span><span class="typ">Windows</span><span class="pln">\\</span><span class="typ">System32</span><span class="str">')
&gt;&gt;&gt; Path.cwd()
WindowsPath('</span><span class="pln">C</span><span class="pun">:/</span><span class="typ">Windows</span><span class="pun">/</span><span class="typ">System32</span><span class="str">')</span></pre>

<p>
	لاحظ أن مجلد العمل الحالي هو <code>C:\Users\Al\AppData\Local\Programs\Python\Python37</code> لذا إذا استعملنا اسم الملف <code>project.docx</code> فإنه سيشير إلى المسار <code>C:\Users\Al\AppData\Local\Programs\Python\Python37\project.docx</code>. حينما بدلنا مجلد العمل الحالي إلى <code>C:\Windows\System32</code> فسيفسر <code>project.docx</code> إلى المسار <code>C:\Windows\System32\project.docx</code>.
</p>

<p>
	ستظهر بايثون رسالة خطأ حين محاولة تغيير مجلد العمل الحالي إلى مجلد غير موجود:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_22" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">chdir</span><span class="pun">(</span><span class="str">'C:/ThisFolderDoesNotExist'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;stdin&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">FileNotFoundError</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="typ">WinError</span><span class="pln"> </span><span class="lit">2</span><span class="pun">]</span><span class="pln"> </span><span class="typ">The</span><span class="pln"> system cannot find the file specified</span><span class="pun">:</span><span class="pln">
</span><span class="str">'C:/ThisFolderDoesNotExist'</span></pre>

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

<p>
	الدالة <code>os.getcwd()‎</code> هي الطريقة القديمة للحصول على سلسلة نصية تمثل مجلد العمل الحالي.
</p>

<h3 id="-4">
	مجلد المنزل
</h3>

<p>
	يمتلك جميع المستخدمون مجلدًا خاصًا بهم يسمى مجلد المنزل home directory، ويمكننا الحصول على كائن <code>Path</code> لمجلد المنزل باستدعاء Path.home()<code>‎</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_24" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">home</span><span class="pun">()</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al'</span><span class="pun">)</span></pre>

<p>
	توجد مجلدات المنزل عادةً في مكان محدد يختلف حسب نظام تشغيلك:
</p>

<ul>
	<li>
		في ويندوز تكون في <code>C:\Users</code>.
	</li>
	<li>
		في ماك تكون في <code>‎/Users</code>.
	</li>
	<li>
		في لينكس تكون في <code>‎/home</code>.
	</li>
</ul>

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

<h3 id="-5">
	المسارات النسبية والمسارات المطلقة
</h3>

<p>
	هنالك طريقتان لتحديد مسار ملف:
</p>

<ul>
	<li>
		مسار مطلق absolute path، الذي يبدأ من المجلد الجذر.
	</li>
	<li>
		مسار نسبي relative path، الذي يبدأ من مجلد العمل الحالي للبرنامج.
	</li>
</ul>

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

<p>
	يوضح الشكل 3 بعض الملفات والمجلدات ويكون مجلد العمل الحالي فيه هو <code>C:\olive</code>، وفيه مسارات الملفات والمجلدات كلها المطلقة والنسبية.
</p>

<p style="text-align: center;">
	<img alt="000057.png" class="ipsImage ipsImage_thumbnailed" data-fileid="150983" data-ratio="51.09" data-unique="cl9pi81qs" width="685" src="https://academy.hsoub.com/uploads/monthly_2024_06/000057.png.da2968a6b3901540f41cdfb6f3c707d1.png">
</p>

<p style="text-align: center;">
	الشكل 3: المسارات المطلقة والنسبية
</p>

<p>
	لاحظ أن ‎.\‎ في بداية المسارات النسبية اختيارية، إذ يشير <code>‎.\spam.txt</code> و <code>spam.txt</code> إلى نفس الملف.
</p>

<h3 id="osmakedires">
	إنشاء مجلدات جديدة باستخدام الدالة os.makedires()‎
</h3>

<p>
	يمكن لبرامجك إنشاء مجلدات جديدة باستخدام الدالة os.makedires()<code>‎</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_26" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> os
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">makedirs</span><span class="pun">(</span><span class="str">'C:\\delicious\\walnut\\waffles'</span><span class="pun">)</span></pre>

<p>
	سينتشئ المثال السابق المجلد <code>C:\delicious</code> وبداخله المجلد <code>walnut</code> وبداخله المجلد <code>waffles.</code> فالدالة <code>os.makedires()‎</code> ستنشِئ أي مجلدات لازمة غير موجودة مسبقًا.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150978" href="https://academy.hsoub.com/uploads/monthly_2024_06/000129.jpg.79d6a9f00b215b250e0691a118aaa552.jpg" rel=""><img alt="000129" class="ipsImage ipsImage_thumbnailed" data-fileid="150978" data-unique="xx5si8imi" src="https://academy.hsoub.com/uploads/monthly_2024_06/000129.jpg.79d6a9f00b215b250e0691a118aaa552.jpg"> </a>
</p>

<p style="text-align: center;">
	الشكل 4: ناتج تنفيذ os.makedirs('C:\delicious\walnut\waffles')<code>‎</code>
</p>

<p>
	لإنشاء مجلد من كائن <code>Path</code> فيمكننا استدعاء التابع <code>mkdir()‎</code>، فمثلًا سأنشِئ المجلد <code>spam</code> في مجلد المنزل في حاسوبي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_28" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> pathlib </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Path</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="pln">r</span><span class="str">'C:\Users\Al\spam'</span><span class="pun">).</span><span class="pln">mkdir</span><span class="pun">()</span></pre>

<p>
	لاحظ أن التابع <code>mkdir()‎</code> يستطيع إنشاء مجلد واحد فقط، ولن ينشِئ مجلدات فرعية كما في الدالة <code>os.makedirs()‎</code>.
</p>

<h3 id="-6">
	التعامل مع المسارات النسبية والمطلقة
</h3>

<p>
	توفر الوحدة <code>pathlib</code> توابع للتحقق إن كان أحد المسارات نسبيًا أو مطلقًا، وتستطيع إعادة المسار المطلق من مسارٍ نسبي.
</p>

<p>
	سيعيد استدعاء التابع <code>is_absolute()‎</code> على كائن <code>Path</code> القيمة <code>True</code> إذا كان يمثل مسارًا مطلقًا أو <code>False</code> إذا كان يمثل مسارًا نسبيًا. تذكر أن تستعمل مسارات موجودة في حاسوبك في الأمثلة القادمة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_30" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">cwd</span><span class="pun">()</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/AppData/Local/Programs/Python/Python37'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">cwd</span><span class="pun">().</span><span class="pln">is_absolute</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'spam/olive/eggs'</span><span class="pun">).</span><span class="pln">is_absolute</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">False</span></pre>

<p>
	للحصول على مسار مطلق من مسار نسبي يمكننا وضع Path.cwd() /<code>‎</code> قبل كائن <code>Path</code>، فحينما نقول «مسار نسبي» فهذا يعني أن المسار منسوب إلى مجلد العمل الحالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_32" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'my/relative/path'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'my/relative/path'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">cwd</span><span class="pun">()</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'my/relative/path'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/AppData/Local/Programs/Python/Python37/my/relative/
path'</span><span class="pun">)</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_34" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'my/relative/path'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'my/relative/path'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">home</span><span class="pun">()</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'my/relative/path'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/my/relative/path'</span><span class="pun">)</span></pre>

<p>
	تمتلك الوحدة <code>os.path</code> عددًا من الدوال المفيدة المتعلقة بالمسارات النسبية والمطلقة:
</p>

<ul>
	<li>
		ستعيد <code>os.path.abspath(path)‎</code> سلسلةً نصية فيها المسار المطلق للوسيط الممرر إليها، وهذه أسهل طريقة لتحويل مسار نسبي إلى مسار مطلق.
	</li>
	<li>
		ستعيد <code>os.path.isabs(path)‎</code> القيمة <code>True</code> إن كان الوسيط الممرر مسارًا مطلقًا و <code>False</code> إذا كان مسارًا نسبيًا.
	</li>
	<li>
		ستعيد os.path.relpath(path, start)<code>‎</code> سلسلةً نصيةً للمسار النسبي للمسار <code>path</code> بدءًا من المسار <code>start.</code> إذا لم نوفر المعامل <code>start</code> فسيستعمل مجلد العمل الحالي بدلًا منه.
	</li>
</ul>

<p>
	لنجرب الدوال السابقة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_36" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">abspath</span><span class="pun">(</span><span class="str">'.'</span><span class="pun">)</span><span class="pln">

</span><span class="str">'C:\\Users\\Al\\AppData\\Local\\Programs\\Python\\Python37'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">abspath</span><span class="pun">(</span><span class="str">'.\\Scripts'</span><span class="pun">)</span><span class="pln">
</span><span class="str">'C:\\Users\\Al\\AppData\\Local\\Programs\\Python\\Python37\\Scripts'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">isabs</span><span class="pun">(</span><span class="str">'.'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">isabs</span><span class="pun">(</span><span class="pln">os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">abspath</span><span class="pun">(</span><span class="str">'.'</span><span class="pun">))</span><span class="pln">
</span><span class="kwd">True</span></pre>

<p>
	ولمّا كان المسار <code>C:\Users\Al\AppData\Local\Programs\Python\Python37</code> هو مجلد العمل الحالي حين استدعاء الدالة <code>os.path.abspath()‎</code>، فسيكون المجلد . (نقطة واحدة) هو المسار المطلق لمجلد العمل الحالي '<code>C:\\Users\\Al\\AppData\\Local\\Programs\\Python\\Python37'</code>.
</p>

<p>
	لنجرب الدالة os.path.relpath()<code>‎</code> في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_38" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">relpath</span><span class="pun">(</span><span class="str">'C:\\Windows'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'C:\\'</span><span class="pun">)</span><span class="pln">
</span><span class="str">'Windows'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">relpath</span><span class="pun">(</span><span class="str">'C:\\Windows'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'C:\\spam\\eggs'</span><span class="pun">)</span><span class="pln">
</span><span class="str">'..\\..\\Windows'</span></pre>

<p>
	إذا امتلك المسار النسبي نفس الأب لمجلد العمل الحالي كما في <code>'C:\\Windows'</code> و <code>'C:\\spam\\eggs'</code> فيمكن استخدام النقطتين .. للوصول إلى المجلد الأب.
</p>

<h3 id="-7">
	الحصول على أقسام المسار
</h3>

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

<p style="text-align: center;">
	<img alt="000033.png" class="ipsImage ipsImage_thumbnailed" data-fileid="150980" data-ratio="111.37" data-unique="lovlmtqc7" width="255" src="https://academy.hsoub.com/uploads/monthly_2024_06/000033.png.4eebc0156fd2b8d2f3b49429172201c0.png">
</p>

<p style="text-align: center;">
	الشكل 5: أجزاء المسار (ويندوز في الأعلى، ولينكس أو ماك في الأسفل)
</p>

<p>
	تتألف مسارات الملفات من الأقسام الآتية:
</p>

<ul>
	<li>
		المرساة anchor وهي المجلد الجذر root directory في نظام الملفات.
	</li>
	<li>
		المحرك drive في ويندوز وهو حرف واحد يشير إلى القرص المستخدم.
	</li>
	<li>
		الأب parent وهو مسار المجلد الذي يحتوي على الملف.
	</li>
	<li>
		اسم الملف name وهو يتألف من الاسم الأساسي stem والامتداد أو اللاحقة suffix.
	</li>
</ul>

<p>
	لاحظ أن كائنات <code>Path</code> تمتلك الخاصية <code>drive</code> في ويندوز، لكنها غير موجودة في ماك أو لينكس. لاحظ أيضًا أن الخاصية <code>drive</code> لا تتضمن أول خط مائل خلفي.
</p>

<p>
	لنجرب هذه الخاصيات على أحد المسارات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_40" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> p </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'C:/Users/Al/spam.txt'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> p</span><span class="pun">.</span><span class="pln">anchor
</span><span class="str">'C:\\'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> p</span><span class="pun">.</span><span class="pln">parent </span><span class="com"># لن يعيد سلسلة نصية بل كائن Path</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> p</span><span class="pun">.</span><span class="pln">name
</span><span class="str">'spam.txt'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> p</span><span class="pun">.</span><span class="pln">stem
</span><span class="str">'spam'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> p</span><span class="pun">.</span><span class="pln">suffix
</span><span class="str">'.txt'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> p</span><span class="pun">.</span><span class="pln">drive
</span><span class="str">'C:'</span></pre>

<p>
	ستعيد هذه الخاصيات سلاسل نصية باستثناء الخاصية <code>parent</code> التي ستعيد كائن <code>Path</code> آخر.
</p>

<p>
	تمنحنا الخاصية <code>parents</code> (التي تختلف عن الخاصية parent السابقة) وصولًا إلى كائنات <code>Path</code> للمجلدات الأب مع فهرس رقمي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_42" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">cwd</span><span class="pun">()</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/AppData/Local/Programs/Python/Python37'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">cwd</span><span class="pun">().</span><span class="pln">parents</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/AppData/Local/Programs/Python'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">cwd</span><span class="pun">().</span><span class="pln">parents</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/AppData/Local/Programs'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">cwd</span><span class="pun">().</span><span class="pln">parents</span><span class="pun">[</span><span class="lit">2</span><span class="pun">]</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/AppData/Local'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">cwd</span><span class="pun">().</span><span class="pln">parents</span><span class="pun">[</span><span class="lit">3</span><span class="pun">]</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/AppData'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">cwd</span><span class="pun">().</span><span class="pln">parents</span><span class="pun">[</span><span class="lit">4</span><span class="pun">]</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">cwd</span><span class="pun">().</span><span class="pln">parents</span><span class="pun">[</span><span class="lit">5</span><span class="pun">]</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">cwd</span><span class="pun">().</span><span class="pln">parents</span><span class="pun">[</span><span class="lit">6</span><span class="pun">]</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/'</span><span class="pun">)</span></pre>

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

<p>
	ستعيد الدالة os.path.dirname(path)<code>‎</code> سلسلةً نصيةً فيها كل ما يسبق آخر خط مائل في المعامل <code>path</code>، بينما ستعيد <code>os.path.basename(path)‎</code> سلسلةً نصيةً فيها كل ما يلي آخر خط مائل في المعامل <code>path</code>. الشكل 6 يوضح مخرجات الدالتين السابقتين:
</p>

<p style="text-align: center;">
	<img alt="000022.png" class="ipsImage ipsImage_thumbnailed" data-fileid="150981" data-ratio="23.12" data-unique="72t63drcm" width="372" src="https://academy.hsoub.com/uploads/monthly_2024_06/000022.png.4831b0e2d1273accb1e36295c7172a56.png">
</p>

<p style="text-align: center;">
	الشكل 6: اسم المجلد dirname واسم الملف basename في الوحدة os.path
</p>

<p>
	لنجربها عمليًا في الطرفية التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_44" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> calcFilePath </span><span class="pun">=</span><span class="pln"> </span><span class="str">'C:\\Windows\\System32\\calc.exe'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">basename</span><span class="pun">(</span><span class="pln">calcFilePath</span><span class="pun">)</span><span class="pln">
</span><span class="str">'calc.exe'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">dirname</span><span class="pun">(</span><span class="pln">calcFilePath</span><span class="pun">)</span><span class="pln">
</span><span class="str">'C:\\Windows\\System32'</span></pre>

<p>
	إذا احتجت إلى اسم المجلد واسم الملف معًا، فيمكنك استدعاء الدالة <code>os.path.split()‎</code> للحصول على صف فيه سلسلتين نصيتين كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_46" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> calcFilePath </span><span class="pun">=</span><span class="pln"> </span><span class="str">'C:\\Windows\\System32\\calc.exe'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="pln">calcFilePath</span><span class="pun">)</span><span class="pln">
</span><span class="pun">(</span><span class="str">'C:\\Windows\\System32'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'calc.exe'</span><span class="pun">)</span></pre>

<p>
	لاحظ أنك تستطيع إنشاء نفس الصف السابق باستدعاء الدالتين <code>os.path.dirname()‎</code> و os.path.basename()<code>‎</code> بنفسك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_48" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">dirname</span><span class="pun">(</span><span class="pln">calcFilePath</span><span class="pun">),</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">basename</span><span class="pun">(</span><span class="pln">calcFilePath</span><span class="pun">))</span><span class="pln">
</span><span class="pun">(</span><span class="str">'C:\\Windows\\System32'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'calc.exe'</span><span class="pun">)</span></pre>

<p>
	لكن استخدام <code>os.path.split()‎</code> سيوفر عليك بعض الوقت أحيانًا.
</p>

<p>
	لاحظ أن الدالة <code>os.path.split()‎</code> لا تأخذ مسار أحد الملفات وتعيد قائمةً من السلاسل النصية تمثل كل مجلد، وإنما علينا استخدام الدالة <code>split()‎</code> الخاصة بالسلاسل النصية وتقسيم المسار عند كل فاصل <code>os.sep</code> (لاحظ أن الفاصل <code>sep</code> موجود في <code>os</code> وليس <code>os.path</code>). يتمثل المتغير <code>os.sep</code> الفاصل بين المجلدات في نظام التشغيل المستخدم، وهو <code>'\\</code>' في ويندوز و <code>'/'</code> في ماك ولينكس:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_50" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> calcFilePath</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="pln">os</span><span class="pun">.</span><span class="pln">sep</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="str">'C:'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Windows'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'System32'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'calc.exe'</span><span class="pun">]</span></pre>

<p>
	سعيد المثال السابق جميع أقسام المسار كقائمة من السلاسل النصية.
</p>

<p>
	سيكون أول عنصر في القائمة المعادة في أنظمة ماك ولينكس هو سلسلة نصية فارغة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_52" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'/usr/bin'</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="pln">os</span><span class="pun">.</span><span class="pln"> sep</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="str">''</span><span class="pun">,</span><span class="pln"> </span><span class="str">'usr'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bin'</span><span class="pun">]</span></pre>

<h3 id="-8">
	الحصول على حجم ملف ومحتويات مجلد
</h3>

<p>
	بعد أن تعلمنا كيف نتعامل مع مسارات الملفات والمجلدات، يمكننا أن نبدأ بجمع المعلومات حولها. توفر الوحدة <code>os.path</code> ما يلزم لمعرفة الحجم التخزيني لملفٍ ما بالبايت، أو للملفات والمجلدات الموجودة في مجلد معين.
</p>

<ul>
	<li>
		استدعاء <code>os.path.getsize(path)‎</code> سيعيد الحجم التخزيني للملف الموجود في المسار <code>path</code> بالبايت.
	</li>
	<li>
		استدعاء <code>os.listdir(path)‎</code> سيعيد قائمة list فيها أسماء كل الملفات الموجودة في المسار <code>path</code>، لاحظ أننا استعملنا هنا الوحدة <code>os</code> وليس <code>os.path</code>.
	</li>
</ul>

<p>
	لنجرب هذه الدوال في الطرفية التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_54" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">getsize</span><span class="pun">(</span><span class="str">'C:\\Windows\\System32\\calc.exe'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">27648</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">listdir</span><span class="pun">(</span><span class="str">'C:\\Windows\\System32'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="str">'0409'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'12520437.cpx'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'12520850.cpx'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'5U877.ax'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'aaclient.dll'</span><span class="pun">,</span><span class="pln">
</span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">
</span><span class="str">'xwtpdui.dll'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'xwtpw32.dll'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'zh-CN'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'zh-HK'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'zh-TW'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'zipfldr.dll'</span><span class="pun">]</span></pre>

<p>
	كما هو واضح، حجم الملف <code>calc.exe</code> في حاسوبي هو 27,648 بايت، ولدي الكثير من الملفات في المسار <code>C:\Windows\system32</code>، وإذا أردت الحصول على الحجم التخزيني لكل الملفات في هذا المجلد فسأستخدم os.path.getsize()<code>‎</code> و <code>os.listdir()‎</code> معًا.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_56" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> totalSize </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> filename </span><span class="kwd">in</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">listdir</span><span class="pun">(</span><span class="str">'C:\\Windows\\System32'</span><span class="pun">):</span><span class="pln">
      totalSize </span><span class="pun">=</span><span class="pln"> totalSize </span><span class="pun">+</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">getsize</span><span class="pun">(</span><span class="pln">os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="str">'C:\\Windows\\System32'</span><span class="pun">,</span><span class="pln"> filename</span><span class="pun">))</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">totalSize</span><span class="pun">)</span><span class="pln">
</span><span class="lit">2559970473</span></pre>

<p>
	سأمر بحلقة التكرار على كل ملف موجود في المجلد <code>C:\Windows\System32</code> وسأزيد قيمة المتغير <code>totalSize</code> بمقدار الحجم التخزيني لكل ملف، لاحظ أنه حين استدعاء <code>os.path.getsize()‎</code> فنستخدم <code>os.path.join()‎</code> لإضافة اسم المجلد إلى اسم الملف الحالي.
</p>

<p>
	ستضاف القيمة العددية المعادة من <code>os.path.getsize()‎</code> إلى قيمة <code>totalSize</code>، وبعد إنهاء المرور على جميع الملفات فسنطبع قيمة <code>totalSize</code> لمعرفة حجم المجلد <code>C:\Windows\System32</code> التخزيني.
</p>

<h3 id="glob">
	الحصول على قائمة من الملفات التي تطابق نمطًا معينًا باستخدام glob()‎
</h3>

<p>
	إذا أردت العمل على ملفات محددة فمن الأسهل استخدام التابع <code>glob()‎</code> بدلًا من <code>listdir()‎</code>، إذ تملك كائنات <code>Path</code> التابع <code>glob()‎</code> للحصول على قائمة الملفات الموجودة داخل مجلد وفقًا لنمط يسمى Glob pattern، والتي تعرف أيضًا بالمحارف البديلة wildcard characters وهي نسخة مبسطة من التعابير النمطية التي يشيع استخدامها في سطر الأوامر (وتسمى هناك بالتوسعات expansion).
</p>

<p>
	يعيد التابع <code>glob()‎</code> كائنًا مولدًا generator object (وهو خارج عن سياق هذا الكتاب)، الذي يمكننا تمريره إلى الدالة list()<code>‎</code> لتسهيل التعامل معه:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_58" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> p </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'C:/Users/Al/Desktop'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> p</span><span class="pun">.</span><span class="pln">glob</span><span class="pun">(</span><span class="str">'*'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">generator object </span><span class="typ">Path</span><span class="pun">.</span><span class="pln">glob at </span><span class="lit">0x000002A6E389DED0</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">p</span><span class="pun">.</span><span class="pln">glob</span><span class="pun">(</span><span class="str">'*'</span><span class="pun">))</span><span class="pln"> 
</span><span class="pun">[</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/Desktop/1.png'</span><span class="pun">),</span><span class="pln"> </span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/
Desktop/22-ap.pdf'</span><span class="pun">),</span><span class="pln"> </span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/Desktop/cat.jpg'</span><span class="pun">),</span><span class="pln">
  </span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/Desktop/zzz.txt'</span><span class="pun">)]</span></pre>

<p>
	رمز النجمة * يعني "مجموعة من أي نوع من المحارف"، وبالتالي سيعيد p.glob('*')<code>‎</code> مولدًا فيه جميع الملفات الموجودة في المسار المخزن في p. وكما في التعابير النمطية، يمكننا كتابة أنماط معقدة بعض الشيء:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_63" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">p</span><span class="pun">.</span><span class="pln">glob</span><span class="pun">(</span><span class="str">'*.txt'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># قائمة بكل الملفات النصية</span><span class="pln">
</span><span class="pun">[</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/Desktop/foo.txt'</span><span class="pun">),</span><span class="pln">
  </span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/Desktop/zzz.txt'</span><span class="pun">)]</span></pre>

<p>
	سيعيد النمط <code>'‎*.txt'</code> كل الملفات التي تبدأ بأي مجموعة من المحارف طالما أنها تنتهي بالسلسلة النصية <code>'‎.txt'</code>، وهو عادةً امتداد الملفات النصية. أما رمز إشارة الاستفهام <code>?</code> فيعني أي محرف واحد:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_60" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">p</span><span class="pun">.</span><span class="pln">glob</span><span class="pun">(</span><span class="str">'project?.docx'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/Desktop/project1.docx'</span><span class="pun">),</span><span class="pln"> </span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/
Desktop/project2.docx'</span><span class="pun">),</span><span class="pln">
  </span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/Desktop/project9.docx'</span><span class="pun">)]</span></pre>

<p>
	التعبير <code>'project?.docx'</code> سيعيد <code>'project1.docx'</code> أو <code>'project5.docx'</code>، لكنه لن يطابق <code>'project10.docx'</code> لأن رمز علامة الاستفهام <code>?</code> سيطابق محرفًا واحدًا فقط، لذا لن يستطيع مطابقة محرفين '10'.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_65" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">p</span><span class="pun">.</span><span class="pln">glob</span><span class="pun">(</span><span class="str">'*.?x?'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/Desktop/calc.exe'</span><span class="pun">),</span><span class="pln"> </span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/
Desktop/foo.txt'</span><span class="pun">),</span><span class="pln">
  </span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">
</span><span class="typ">WindowsPath</span><span class="pun">(</span><span class="str">'C:/Users/Al/Desktop/zzz.txt'</span><span class="pun">)]</span></pre>

<p>
	التعبير <code>'‎*.?x?‎'</code> سيعيد جميع الملفات التي لها أي اسم لكنها تنتهي بلاحقة تتألف من 3 محارف، والمحرف الوسط بينها هو 'x'.
</p>

<p>
	يسهل علينا التابع <code>glob()‎</code> تحديد الملفات التي نريدها باختيار الملفات التي يطابق اسمها نمطًا معينًا. سنستخدم هنا الحلقة <code>for</code> للمرور على المولد generator المولد من التابع <code>glob()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_67" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> p </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'C:/Users/Al/Desktop'</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"> textFilePathObj </span><span class="kwd">in</span><span class="pln"> p</span><span class="pun">.</span><span class="pln">glob</span><span class="pun">(</span><span class="str">'*.txt'</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">textFilePathObj</span><span class="pun">)</span><span class="pln"> </span><span class="com"># طباعة كائن Path كسلسلة نصية</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">
C</span><span class="pun">:</span><span class="pln">\Users\Al\Desktop\foo</span><span class="pun">.</span><span class="pln">txt
C</span><span class="pun">:</span><span class="pln">\Users\Al\Desktop\spam</span><span class="pun">.</span><span class="pln">txt
C</span><span class="pun">:</span><span class="pln">\Users\Al\Desktop\zzz</span><span class="pun">.</span><span class="pln">txt</span></pre>

<p>
	إذا أردت إجراء نفس العملية على جميع الملفات الموجودة في المجلد، فيمكنك أن تستعمل حينها <code>os.listdir(p)‎</code> أو <code>p.glob('*')‎</code>.
</p>

<h3 id="-9">
	التأكد من المسارات
</h3>

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

<ul>
	<li>
		p.exists()‎ القيمة <code>True</code> إذا كان المسار موجودًا، أو <code>False</code> إن لم يكن موجودًا.
	</li>
	<li>
		p.is_file()‎ القيمة <code>True</code> إن كان المسار موجودًا ويشير إلى ملف، أو <code>False</code> خلاف ذلك.
	</li>
	<li>
		p.is_dir()‎ القيمة <code>True</code> إذا كان المسار موجودًا ويشير إلى مجلد، أو <code>False</code> خلاف ذلك.
	</li>
</ul>

<p>
	دعني أجرب هذه التوابع على حاسوبي الشخصي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_69" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> winDir </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'C:/Windows'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> notExistsDir </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'C:/This/Folder/Does/Not/Exist'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> calcFile </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'C:/Windows
/System32/calc.exe'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> winDir</span><span class="pun">.</span><span class="pln">exists</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> winDir</span><span class="pun">.</span><span class="pln">is_dir</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> notExistsDir</span><span class="pun">.</span><span class="pln">exists</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> calcFile</span><span class="pun">.</span><span class="pln">is_file</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> calcFile</span><span class="pun">.</span><span class="pln">is_dir</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">False</span></pre>

<p>
	إذا كنت تستعمل ويندوز فيمكنك أن تتحقق إن كان قرص التخزين المؤقت («الفلاشة») موصولًا إلى الحاسوب عبر التابع exists()<code>‎</code>، فمثلًا لو أردت التحقق أن القرص المسمى D:`‎` موجود على حاسوبي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_71" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> dDrive </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'D:/'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> dDrive</span><span class="pun">.</span><span class="pln">exists</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">False</span></pre>

<p>
	يبدو أنني نسيت وصل القرص إلى الحاسوب.
</p>

<p>
	الوحدة القديمة <code>os.path</code> تستطيع إنجاز نفس المهمة باستخدام <code>os.path.exists(path)‎</code> و os.path.isfile(path)<code>‎</code> و <code>os.path.isdir(path)‎</code>، التي تعمل ملف مكافأتها في كائنات <code>Path</code>. وبدءًا من الإصدار بايثون 3.6 أصبحت تقبل هذه التوابع كائنات <code>Path</code> إضافةً إلى سلاسل نصية تحتوي على مسارات الملفات.
</p>

<h2 id="-10">
	عملية قراءة الملفات والكتابة إليها
</h2>

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

<p>
	الدوال التي سنشرحها في الأقسام الآتية تعمل على الملفات النصية البسيطة، التي هي ملفات تحتوي على محارف نصية دون أن تحتوي على معلومات التنسيقات مثل الخطوط أو الألوان أو خلاف ذلك، ومن الأمثلة على الملفات النصية البسيطة هي ملفات txt أو py التي تحتوي على شيفرات بايثون. يمكن فتح هذه الملفات باستخدام المفكرة Notepad في ويندوز، أو TextEdit في ماك، أو Kate أو Gedit في لينكس. وتستطيع أن تفتح هذه الملفات في برامجك وتعاملها كسلاسل نصية عادية.
</p>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150979" href="https://academy.hsoub.com/uploads/monthly_2024_06/000150.jpg.a5d8db356034861c56c5a85ccba0fc6a.jpg" rel=""><img alt="000150" class="ipsImage ipsImage_thumbnailed" data-fileid="150979" data-unique="ykhk14yfc" src="https://academy.hsoub.com/uploads/monthly_2024_06/000150.jpg.a5d8db356034861c56c5a85ccba0fc6a.jpg"> </a>
</p>

<p style="text-align: center;">
	الشكل 7: برنامج calc.exe مفتوح في المفكرة
</p>

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

<p>
	التابع <code>read_text()‎</code> في الوحدة <code>pathlib</code> تعيد سلسلةً نصية فيها كل محتويات الملف النصي، بينما يكتب التابع <code>write_text()‎</code> ما يمرر إليه إلى ملف نصي جديد (أو يعيد الكتابة فوق ملف موجود مسبقًا):
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_73" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> pathlib </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Path</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> p </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">(</span><span class="str">'spam.txt'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> p</span><span class="pun">.</span><span class="pln">write_text</span><span class="pun">(</span><span class="str">'Hello, world!'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">13</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> p</span><span class="pun">.</span><span class="pln">read_text</span><span class="pun">()</span><span class="pln">
</span><span class="str">'Hello, world!'</span></pre>

<p>
	سننشئ ملفًا باسم <code>spam.txt</code> فيه المحتويات <code>'Hello, world!‎'</code>، لاحظ أن التابع <code>write_text()‎</code> قد أعاد الرقم 13 الذي يشير إلى عدد المحارف التي كتبت إلى الملف (ونتجاهل تخزين هذا الرقم عادةً)، ويقرأ التابع <code>read_text()‎</code> محتويات الملف الجديد ويعيدها على شكل سلسلة نصية.
</p>

<p>
	تذكر أن توابع الكائن <code>Path</code> توفر الأمور الأساسية في التعامل مع الملفات؛ والطريقة الأشيع لقراءة الملفات تكون عبر الدالة <code>open()‎</code> والكائن <code>File</code>. هنالك خطوات ثلاث لقراءة أو كتابة الملفات في بايثون:
</p>

<ol>
	<li>
		استدعاء الدالة <code>open()‎</code> لإعادة الكائن <code>File</code>.
	</li>
	<li>
		استدعاء التابع <code>read()‎</code> أو <code>write()‎</code> على الكائن <code>File</code>.
	</li>
	<li>
		إغلاق الملف باستدعاء التابع <code>close()‎</code> على الكائن <code>File</code>.
	</li>
</ol>

<p>
	سنشرح هذه الخطوات في الأقسام الآتية.
</p>

<h3 id="open">
	فتح الملفات عبر الدالة open()‎
</h3>

<p>
	لفتح ملف باستخدام الدالة <code>open()‎</code> فنمرر سلسلة نصية تحتوي على مسار الملف الذي نريد فتحه؛ والذي يكون إما مسارًا مطلقًا absolute أو نسبيًا relative. ستعيد الدالة <code>open()‎</code> كائنًا من النوع <code>File</code>.
</p>

<p>
	لنجربها بإنشاء ملف نصي بسيط اسمه <code>hello.txt</code> باستخدام المفكرة أو أي محرر نصوص، وكتابة Hello, World!‎ داخلها وحفظه في مجلد المنزل، ثم كتابة ما يلي في الطرفية التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_75" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> helloFile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="typ">Path</span><span class="pun">.</span><span class="pln">home</span><span class="pun">()</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="str">'hello.txt'</span><span class="pun">)</span></pre>

<p>
	تقبل الدالة <code>open()‎</code> السلاسل النصية أيضًا، فإذا كنت تستخدم ويندوز فاكتب:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_77" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> helloFile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'C:\\Users\\your_home_folder\\hello.txt'</span><span class="pun">)</span></pre>

<p>
	أما إذا كان نظامك ماك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_79" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> helloFile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'/Users/your_home_folder/hello.txt'</span><span class="pun">)</span></pre>

<p>
	تذكر أن تبدل الكلمة your<em>home</em>folder باسم المستخدم في حاسوبك، فلو كان hsoub مثلًا فستدخل <code>'C:\\Users\\hsoub\\hello.txt'</code> في ويندوز؛ لاحظ أن الدالة open()<code>‎</code> أصبحت تقبل كائنات <code>Path</code> بدءًا من إصدار بايثون 3.6، وكان عليك استخدام السلاسل النصية فقط فيما سبق.
</p>

<p>
	ستفتح هذه الأوامر الملف في وضع "قراءة الملفات النصية" أو اختصارًا "وضع القراءة"، وحينما يفتح الملف في وضع القراءة فتسمح لنا بايثون بقراءة الملفات من الملف فقط، ولا يمكنك أن تكتب عليه أو تعدله بأي شكل. لكن إذا أردت أن تحدد أنك تريد فتح الملف بوضع القراءة بوضوح فمرر القيمة <code>'r'</code> كثاني وسيط إلى الدالة <code>open()‎</code>، أي أن open('/Users/Al/hello.txt', 'r')<code>‎</code> و open('/Users/Al/hello.txt')<code>‎</code> متكافئتان تمامًا.
</p>

<p>
	سيعيد استدعاء الدالة open()<code>‎</code> كائن <code>File</code>، ويمثل كائن <code>File</code> ملفًا على حاسوبك، وهو نوع مختلف من القيم في بايثون مثله كمثل القوائم أو القواميس التي تعرفت عليها مسبقًا.
</p>

<p>
	خزنّا في المثال السابق كائن <code>File</code> في المتغير <code>helloFile</code>، ويمكنك أن تستسخدمه لأي عمليات قراءة أو كتابة مستقبلًا باستدعاء التوابع المناسبة على الكائن <code>File</code> المخزن في المتغير <code>helloFile</code>.
</p>

<h3 id="-11">
	قراءة محتويات الملفات
</h3>

<p>
	أصبح لدينا الآن كائن <code>File</code>، ويمكننا أن نبدأ بقراءة كامل محتويات الملف كسلسلة نصية، وذلك عبر التابع <code>read()‎</code>، لنكمل مثالنا السابق الذي فيه المتغير <code>helloFile</code> بكتابة ما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_81" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> helloContent </span><span class="pun">=</span><span class="pln"> helloFile</span><span class="pun">.</span><span class="pln">read</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> helloContent
</span><span class="str">'Hello, world!'</span></pre>

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

<p>
	بدلًا من ذلك، يمكنك استخدام التابع readlines()<code>‎</code> للحصول على قائمة list فيها سلاسل نصية من الملف، وكل سلسلة نصية تمثل سطرًا فيه، فمثلًا لو كان لدينا ملف اسمه <code>sonnet29.txt</code> في نفس المجلد الذي فيه الملف <code>hello.txt</code> وكتبنا فيه النص الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_83" style=""><span class="typ">When</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> disgrace </span><span class="kwd">with</span><span class="pln"> fortune </span><span class="kwd">and</span><span class="pln"> men</span><span class="str">'s eyes,
I all alone beweep my outcast state,
And trouble deaf heaven with my bootless cries,
And look upon myself and curse my fate,</span></pre>

<p>
	تأكد أنك قد فصلت بين الأسطر الأربعة السابقة كلٌ في سطر مختلف، ثم أدخل ما يلي في الطرفية التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_85" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sonnetFile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="typ">Path</span><span class="pun">.</span><span class="pln">home</span><span class="pun">()</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="str">'sonnet29.txt'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> sonnetFile</span><span class="pun">.</span><span class="pln">readlines</span><span class="pun">()</span><span class="pln">
</span><span class="pun">[</span><span class="typ">When</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> disgrace </span><span class="kwd">with</span><span class="pln"> fortune </span><span class="kwd">and</span><span class="pln"> men</span><span class="str">'s eyes,\n'</span><span class="pun">,</span><span class="pln"> </span><span class="str">' I all alone beweep my
outcast state,\n'</span><span class="pun">,</span><span class="pln"> </span><span class="typ">And</span><span class="pln"> trouble deaf heaven </span><span class="kwd">with</span><span class="pln"> my bootless cries</span><span class="pun">,</span><span class="pln">\n</span><span class="str">', And
look upon myself and curse my fate,'</span><span class="pun">]</span></pre>

<p>
	لاحظ أن كل عنصر من عناصر القائمة (باستثناء آخر واحد) هو سلسلة نصية تنتهي بمحرف السطر الجديد <code>‎\n</code>.
</p>

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

<h3 id="-12">
	الكتابة إلى الملفات
</h3>

<p>
	تسمح لنا بايثون بكتابة محتوى إلى الملفات بشكل يشبه "كتابة" الدالة print()<code>‎</code> للسلاسل النصية إلى الشاشة.
</p>

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

<p>
	وضع الكتابة سيعيد الكتابة فوق ملف موجود ويبدأ من الصفر، كما لو أعدنا إسناد قيمة جديدة إلى متغير. يمكنك فتحت الملف بوضع الكتابة بتمرير <code>'w'</code> كثاني وسيط إلى الدالة <code>open()‎</code>.
</p>

<p>
	أما وضع الإضافة فسيضيف النص إلى نهاية ملف موجود مسبقًا، كما لو أضفنا عنصرًا إلى قائمة موجودة في متغير بدلًا من إعادة الكتابة. مرر 'a' كثاني وسيط إلى الدالة <code>open()‎</code> لفتح الملف في وضع الإضافة.
</p>

<p>
	إذا لم يكن الملف الممرر إلى الدالة <code>open()‎</code> موجودًا فسينشأ ملف جديد في وضع الكتابة والإسناد. لا تنسَ أن تستدعي الدالة close()<code>‎</code> قبل إعادة فتح الملف مجددًا.
</p>

<p>
	لنجرب هذه المفاهيم معًا بكتابة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_87" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> oliveFile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'olive.txt'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'w'</span><span class="pun">)</span><span class="pln">   
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> oliveFile</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="lit">13</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> oliveFile</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> oliveFile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'olive.txt'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'a'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> oliveFile</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">'Olive is not a vegetable.'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">25</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> oliveFile</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> oliveFile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'olive.txt'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> content </span><span class="pun">=</span><span class="pln"> oliveFile</span><span class="pun">.</span><span class="pln">read</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> oliveFile</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</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">content</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> world</span><span class="pun">!</span><span class="pln">
</span><span class="typ">Olive</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> a vegetable</span><span class="pun">.</span></pre>

<p>
	في البداية فتحنا الملف <code>becon.txt</code> بوضع الكتابة، ولعدم وجود الملف <code>becon.txt</code> بعد فإن بايثون تنشئه لنا، واستدعاء التابع <code>write()‎</code> وتمرير السلسلة النصية <code>'Hello, world! /n'</code> سيؤدي إلى كتابتها إلى الملف وإعادة عدد المحارف المكتوبة بما فيها محرف السطر الجديد. ثم أغلقنا في النهاية الملف.
</p>

<p>
	لإضافة نص إلى المحتويات الموجودة لملف بدلًا من استبداله، فسنفتح الملف في وضع الإضافة، وأضفنا السلسلة النصية <code>'Olive is not a vegetable.‎'</code> إلى الملف وأغلقناه.
</p>

<p>
	في النهاية نريد أن نطبع محتويات الملف فاستخدمنا الدالة open()<code>‎</code> لفتح الملف في الوضع الافتراضي وهو وضع القراءة، وخزنّا محتويات الملف في المتغير <code>content</code> ثم أغلقنا الملف وطبعنا محتوياته.
</p>

<p>
	لاحظ أن التابع <code>write()</code> لا يضيف محرف السطر الجديد إلى نهاية السلسلة النصية مثلما تفعل الدالة <code>print()‎</code> لذا عليك أن تضيفه بنفسك. تذكر أنك تستطيع تمرير كائن <code>Path</code> إلى الدالة <code>open()‎</code> بدلًا من سلسلة نصية بسيطة بدءًا من إصدار بايثون 3.6.
</p>

<h2 id="shelve">
	حفظ المتغيرات باستخدام الوحدة shelve
</h2>

<p>
	يمكنك أن تحفظ المتغيرات الموجودة في برامجك إلى ملفات ثنائية باستخدام الوحدة <code>shelve</code>، وبالتالي يمكنك أن تستعيد البيانات إلى المتغيرات من ملف مخزن على حاسوبك.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_89" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> shelve
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> shelfFile </span><span class="pun">=</span><span class="pln"> shelve</span><span class="pun">.</span><span class="pln">open</span><span class="pun">(</span><span class="str">'mydata'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> cats </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Zophie'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Pooka'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Simon'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> shelfFile</span><span class="pun">[</span><span class="str">'cats'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> cats
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> shelfFile</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	لقراءة وكتابة البيانات باستخدام الوحدة <code>shelve</code> عليك أن تستوردها أولًا، ثم تستدعي <code>shelve.open()‎</code> وتمرر إليها اسم الملف ثم تخزن القيم. لاحظ أنك تستطيع التعامل مع القيم كما لو أنها قاموس. بعد أن تنتهي لا تنسَ استدعاء close()<code>‎</code>.
</p>

<p>
	أنشأنا في المثال السابق القائمة cats وكتبنا <code>shelfFile['cats'] = cats</code> لتخزين القائمة في <code>shelfFile</code> كقيمة مرتبطة مع المفتاح <code>'cat'</code> (كما في مفاتيح القواميس). ثم استدعينا <code>close()‎</code> على <code>shelfFile</code>، لاحظ أنه بدءًا من إصدار بايثون 3.7 سيكون عليك تمرير أسماء الملفات إلى <code>open()‎</code> كسلاسل نصية، ولا يمكنك تمرير كائن <code>Path</code>.
</p>

<p>
	بعد تشغيل الشيفرة السابقة في ويندوز، ستجد ثلاثة ملفات جديدة في المجلد وهي <code>mydata.bak</code> و <code>mydata.dat</code> و <code>mydata.dir</code>؛ أما على ماك فسينشَأ ملف واحد باسم <code>mydata.db</code>.
</p>

<p>
	تحتوي هذه الملفات الثنائية على البيانات التي خزنتها «على الرف»؛ ولا تهمك صيغة هذه الملفات الثانية، فكل ما تحتاج إلى معرفته هو ما تفعله الوحدة shelve وليس كيف تفعل ذلك. وهذه الوحدة تريح رأسك من القلق حول كيفية تخزين البرنامج للبيانات.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_91" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> shelfFile </span><span class="pun">=</span><span class="pln"> shelve</span><span class="pun">.</span><span class="pln">open</span><span class="pun">(</span><span class="str">'mydata'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> type</span><span class="pun">(</span><span class="pln">shelfFile</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="kwd">class</span><span class="pln"> </span><span class="str">'shelve.DbfilenameShelf'</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> shelfFile</span><span class="pun">[</span><span class="str">'cats'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">[</span><span class="str">'Zophie'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Pooka'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Simon'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> shelfFile</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	فتحنا في المثال السابق الملف الذي وضعنا فيه البيانات، وتأكدنا أن التخزين سليم إذ أعاد shelfFile['cats']<code>‎</code> نفس القائمة التي خزناها سابقًا، وفي النهاية أغلقنا الملف <code>close()‎</code>.
</p>

<p>
	هنالك تابعان اسمهما <code>keys()‎</code> و <code>values()‎</code> تشبه تلك الموجودة في القواميس التي تعيد قيمةً شبيهة بالقوائم list-like للمفاتيح والقيم الموجودة في الرف. ولأن هذه التوابع تعيد قيمًا شبيهة بالقوائم وليست قوائم حقيقية فيجب عليك تمريرها إلى الدالة <code>list()‎</code> للحصول على قائمة حقيقية تتعامل معها.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_93" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> shelfFile </span><span class="pun">=</span><span class="pln"> shelve</span><span class="pun">.</span><span class="pln">open</span><span class="pun">(</span><span class="str">'mydata'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">shelfFile</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">())</span><span class="pln">
</span><span class="pun">[</span><span class="str">'cats'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">shelfFile</span><span class="pun">.</span><span class="pln">values</span><span class="pun">())</span><span class="pln">
</span><span class="pun">[[</span><span class="str">'Zophie'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Pooka'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Simon'</span><span class="pun">]]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> shelfFile</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	الخلاصة أن الملفات النصية البسيطة مفيدة لتخزين البيانات النصية الأساسية، أما لو أردت حفظ بيانات من برنامج بايثون الذي كتبته، فيمكنك أن تستفيد من الوحدة <code>shelve</code>.
</p>

<h2 id="pprintpformat">
	حفظ المتغيرات مع الدالة pprint.pformat()‎
</h2>

<p>
	إذا كنت تذكر في قسم «تجميل الطباعة» أن الدالة <code>pprint.pprint()‎</code> تطبع محتويات قائمة أو قاموس بتنسيق مخصص، بينما الدالة <code>pprint.pformat()‎</code> تنسق النص وتعيده بدلًا من طباعته مباشرةً.
</p>

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

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_95" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> pprint
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> cats </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[{</span><span class="str">'name'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Zophie'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'desc'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'chubby'</span><span class="pun">},</span><span class="pln"> </span><span class="pun">{</span><span class="str">'name'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Pooka'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'desc'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'fluffy'</span><span class="pun">}]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> pprint</span><span class="pun">.</span><span class="pln">pformat</span><span class="pun">(</span><span class="pln">cats</span><span class="pun">)</span><span class="pln">
</span><span class="str">"[{'desc': 'chubby', 'name': 'Zophie'}, {'desc': 'fluffy', 'name': 'Pooka'}]"</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> fileObj </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'myCats.py'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'w'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> fileObj</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">'cats = '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> pprint</span><span class="pun">.</span><span class="pln">pformat</span><span class="pun">(</span><span class="pln">cats</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="lit">83</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> fileObj</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	استوردنا في هذا المثال الوحدة <code>pprint</code> لكي نستطيع استخدام الدالة <code>pprint.pformat()‎</code>، ولدينا متغير <code>cats</code> فيه قائمة من القواميس؛ ولكي نحتفظ بالقائمة الموجودة في المتغير <code>cats</code> حتى بعد أن نغلق الصدفة التفاعلية فيمكننا استخدام الدالة <code>pprint.pformat()‎</code> لإعادته كسلسلة نصية، ثم بعد حصولنا على السلسلة النصية يمكننا كتابتها إلى ملف وليكن اسمه <code>myCats.py</code>.
</p>

<p>
	تذكر أن الوحدات التي تستوردها العبارة <code>import</code> هي سكربتات بايثون عادية؛ وعندما نحفظ السلسلة النصية المأخوذة من pprint.pformat()<code>‎</code> إلى ملف <code>‎.py</code> فيمكن اعتبار هذا الملف على أنه وحدة يمكن استيرادها مثل أي وحدات بايثون الأخرى.
</p>

<p>
	ولأن سكربتات بايثون هي ملفات نصية بسيط امتدادها <code>‎.py</code> فيمكن لبرامجك أن تولد برامج بايثون أخرى، ويمكنك استيراد تلك البرامج داخل برامجك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_97" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> myCats
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> myCats</span><span class="pun">.</span><span class="pln">cats
</span><span class="pun">[{</span><span class="str">'name'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Zophie'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'desc'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'chubby'</span><span class="pun">},</span><span class="pln"> </span><span class="pun">{</span><span class="str">'name'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Pooka'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'desc'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'fluffy'</span><span class="pun">}]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> myCats</span><span class="pun">.</span><span class="pln">cats</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
</span><span class="pun">{</span><span class="str">'name'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Zophie'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'desc'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'chubby'</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> myCats</span><span class="pun">.</span><span class="pln">cats</span><span class="pun">[</span><span class="lit">0</span><span class="pun">][</span><span class="str">'name'</span><span class="pun">]</span><span class="pln">
</span><span class="str">'Zophie'</span></pre>

<p>
	الفائدة من إنشاء ملف <code>‎.py</code> بسيط بدلًا من حفظ المتغيرات مع الوحدة <code>shelve</code> هو أن الناتج ملف نصي يمكن قراءته وتعديله من أي شخص بمحرر نصي بسيط.
</p>

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

<h2 id="-13">
	مشروع: توليد ملفات اختبارات عشوائية
</h2>

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

<p>
	هذه هي وظيفة البرنامج:
</p>

<ol>
	<li>
		إنشاء 35 اختبار مختلف
	</li>
	<li>
		إنشاء 50 سؤال اختيار من إجابات متعددة لكل اختبار، بترتيب عشوائي
	</li>
	<li>
		توفير الإجابة الصحيحة وثلاث إجابات خطأ لكل سؤال مرتبة ترتيبًا عشوائيًا
	</li>
	<li>
		كتابة الاختبارات إلى 35 ملف نصي
	</li>
	<li>
		كتابة مفاتيح الإجابات الصحيحة إلى 35 ملف نصي
	</li>
</ol>

<p>
	هذا يعني أن الشيفرة عليها أن:
</p>

<ol>
	<li>
		تخزن أسماء الولايات في أمريكا وأسماء عواصمها في قاموس
	</li>
	<li>
		تستدعي <code>open()‎</code> و write()<code>‎</code> و close()<code>‎</code> لكل ملف اختبار وإجابات
	</li>
	<li>
		تستخدم random.shuffle()<code>‎</code> لترتيب الأسئلة والإجابات ترتيبًا عشوائيًا
	</li>
</ol>

<h3 id="1">
	الخطوة 1: تخزين بيانات الاختبار في قاموس
</h3>

<p>
	أول خطوة هي إنشاء بينة السكربت الأساسية وكتابة بيانات الاختبار. أنشِئ ملفًا باسم <code>randomQuizGenerator.py</code> وضع فيه المحتوى الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_99" style=""><span class="pln"> </span><span class="com">#! python3</span><span class="pln">
   </span><span class="com"># randomQuizGenerator.py - إنشاء اختبارات مع أسئلة وإجابات عشوائية</span><span class="pln">
   </span><span class="com"># مع تخزين مفتاح الحل.</span><span class="pln">
</span><span class="pun">➊</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> random
   </span><span class="com"># بيانات الاختبار: أسماء الولايات الأمريكية وعواصمها.</span><span class="pln">
</span><span class="pun">➋</span><span class="pln"> capitals </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'Alabama'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Montgomery'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Alaska'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Juneau'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Arizona'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Phoenix'</span><span class="pun">,</span><span class="pln">
   </span><span class="str">'Arkansas'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Little Rock'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'California'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Sacramento'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Colorado'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Denver'</span><span class="pun">,</span><span class="pln">
   </span><span class="str">'Connecticut'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Hartford'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Delaware'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Dover'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Florida'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Tallahassee'</span><span class="pun">,</span><span class="pln">
   </span><span class="str">'Georgia'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Atlanta'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Hawaii'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Honolulu'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Idaho'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Boise'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Illinois'</span><span class="pun">:</span><span class="pln">
   </span><span class="str">'Springfield'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Indiana'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Indianapolis'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Iowa'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Des Moines'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Kansas'</span><span class="pun">:</span><span class="pln">
   </span><span class="str">'Topeka'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Kentucky'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Frankfort'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Louisiana'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Baton Rouge'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Maine'</span><span class="pun">:</span><span class="pln">
   </span><span class="str">'Augusta'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Maryland'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Annapolis'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Massachusetts'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Boston'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Michigan'</span><span class="pun">:</span><span class="pln">
   </span><span class="str">'Lansing'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Minnesota'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Saint Paul'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Mississippi'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Jackson'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Missouri'</span><span class="pun">:</span><span class="pln">
   </span><span class="str">'Jefferson City'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Montana'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Helena'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Nebraska'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Lincoln'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Nevada'</span><span class="pun">:</span><span class="pln">
   </span><span class="str">'Carson City'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'New Hampshire'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Concord'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'New Jersey'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Trenton'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'New
   Mexico'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Santa Fe'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'New York'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Albany'</span><span class="pun">,</span><span class="pln">
   </span><span class="str">'North Carolina'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Raleigh'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'North Dakota'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Bismarck'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Ohio'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Columbus'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Oklahoma'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Oklahoma City'</span><span class="pun">,</span><span class="pln">
   </span><span class="str">'Oregon'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Salem'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Pennsylvania'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Harrisburg'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Rhode Island'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Providence'</span><span class="pun">,</span><span class="pln">
   </span><span class="str">'South Carolina'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Columbia'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'South Dakota'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Pierre'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Tennessee'</span><span class="pun">:</span><span class="pln">
   </span><span class="str">'Nashville'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Texas'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Austin'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Utah'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Salt Lake City'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Vermont'</span><span class="pun">:</span><span class="pln">
   </span><span class="str">'Montpelier'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Virginia'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Richmond'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Washington'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Olympia'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'West
   Virginia'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Charleston'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Wisconsin'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Madison'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Wyoming'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Cheyenne'</span><span class="pun">}</span><span class="pln">

   </span><span class="com"># توليد 35 اختبار عشوائي.</span><span class="pln">
</span><span class="pun">➌</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> quizNum </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">35</span><span class="pun">):</span><span class="pln">
       </span><span class="com"># TODO: إنشاء ملفات الاختبار والإجابات.</span><span class="pln">

       </span><span class="com"># TODO: كتابة ترويسة الاختبار.</span><span class="pln">

       </span><span class="com"># TODO: تغيير ترتيب الولايات.</span><span class="pln">

       </span><span class="com"># TODO: المرور على 50 سؤال وتوليد إجابات عشوائية.</span></pre>

<p>
	لما كان هذا البرنامج يرتب الأسئلة والإجابات عشوائيًا، فعلينا استيراد الوحدة <code>random</code> ➊ لكي نستطيع استخدام الدوال الخاصة بها. يحتوي المتغير <code>capitals</code> ➋ على قاموس فيه أسماء الولايات الأمريكية كمفتاح وعاصمتها كقيمة. ولأننا نريد كتابة الشيفرة التي تولد ملفات الاختبار والإجابات (أضفناها على أنها TODO حاليًا) فسندخل إلى حلقة التكرار <code>for</code> بعدد 35 مرة ➌، ويمكننا تغيير الرقم وفق متطلبات البرنامج.
</p>

<h3 id="2">
	الخطوة 2: إنشاء ملف الاختبار وتغيير ترتيب الأسئلة عشوائيا
</h3>

<p>
	حان الوقت لبدء العمل على مهام TODO.
</p>

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

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

<p>
	أضف الأسطر الآتية إلى ملف <code>randomQuizGenerator.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_101" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># randomQuizGenerator.py - إنشاء اختبارات مع أسئلة وإجابات عشوائية</span><span class="pln">
</span><span class="com"># مع تخزين مفتاح الحل.</span><span class="pln">

</span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">

</span><span class="com"># توليد 35 اختبار عشوائي.</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> quizNum </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">35</span><span class="pun">):</span><span class="pln">
    </span><span class="com"># إنشاء ملف الاختبارات والإجابات</span><span class="pln">
  </span><span class="pun">➊</span><span class="pln"> quizFile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="pln">f</span><span class="str">'capitalsquiz{quizNum + 1}.txt'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'w'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">➋</span><span class="pln"> answerKeyFile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="pln">f</span><span class="str">'capitalsquiz_answers{quizNum + 1}.txt'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'w'</span><span class="pun">)</span><span class="pln">
     </span><span class="com"># كتابة الترويسة</span><span class="pln">
  </span><span class="pun">➌</span><span class="pln"> quizFile</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">'Name:\n\nDate:\n\nPeriod:\n\n'</span><span class="pun">)</span><span class="pln">
     quizFile</span><span class="pun">.</span><span class="pln">write</span><span class="pun">((</span><span class="str">' '</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">20</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> f</span><span class="str">'State Capitals Quiz (Form{quizNum + 1})'</span><span class="pun">)</span><span class="pln">
     quizFile</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">'\n\n'</span><span class="pun">)</span><span class="pln">

     </span><span class="com"># تغيير ترتيب الولايات</span><span class="pln">
     states </span><span class="pun">=</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">capitals</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">())</span><span class="pln">
  </span><span class="pun">➍</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">shuffle</span><span class="pun">(</span><span class="pln">states</span><span class="pun">)</span><span class="pln">

      </span><span class="com"># TODO: المرور على 50 سؤال وتوليد إجابات عشوائية.</span></pre>

<p>
	ستكون أسماء ملفات الاختبارات على الشكل <code>capitalsquiz&lt;N&gt;.txt</code> حيث <code>&lt;N&gt;</code> هو رقم فريد لكل اختبار يأتي من <code>quizNum</code> الذي هو عدّاد حلقة <code>for</code>. سيخزن ملف مفاتيح الإجابات للاختبار <code>capitalsquiz&lt;N&gt;.txt</code> في ملف باسم <code>capitalsquiz_answers&lt;N&gt;.txt</code>.
</p>

<p>
	في كل دورة في حلقة <code>for</code> ستبدل قيمة <code>{quizNum + 1}</code> في <code>f'capitalsquiz{quizNum + 1}.txt'‎</code> و f'capitalsquiz_answers{quizNum + 1}.txt'<code>‎</code> برقم فريد، وستكون أسماء الملفات لأول مرور باسم <code>capitalsquiz1.txt</code> و <code>capitalsquiz_answers1.txt</code>. ستنشأ هذه الملفات حين استدعاء الدالة <code>open()‎</code> في السطرين ➊ و ➋ حين تمرير الوسيط الثاني 'w' لفتح الملفات في وضع الكتابة.
</p>

<p>
	العبارات <code>write()‎</code> في القسم ➌ تكتب ترويسة الاختبار التي يجب على الطالب أن يملأها؛ ثم سننشِئ قائمة عشوائية فيها أسماء الولايات الأمريكية باستخدام الدالة <code>random.shuffle()‎</code> في السطر ➍، التي تغير ترتيب القيم في أي قائمة تمرر إليها.
</p>

<h3 id="3">
	الخطوة 3: إنشاء خيارات الإجابة
</h3>

<p>
	علينا الآن توليد خيارات إجابات كل سؤال، والتي ستكون اختيار من متعدد من A إلى D، أي أننا سنحتاج إلى إنشاء حلقة <code>for</code> أخرى لتوليد محتوى لكل سؤال من الأسئلة الخميس. ثم ستكون هنالك حلقة <code>for</code> ثالثة داخلها لتوليد الإجابات المحتملة لكل سؤال.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_103" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># randomQuizGenerator.py - إنشاء اختبارات مع أسئلة وإجابات عشوائية</span><span class="pln">
</span><span class="com"># مع تخزين مفتاح الحل.</span><span class="pln">

</span><span class="pun">--</span><span class="pln">snip</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"> questionNum </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">50</span><span class="pun">):</span><span class="pln">

         </span><span class="com"># الحصول على الإجابات الصحيحة والخطأ.</span><span class="pln">
      </span><span class="pun">➊</span><span class="pln"> correctAnswer </span><span class="pun">=</span><span class="pln"> capitals</span><span class="pun">[</span><span class="pln">states</span><span class="pun">[</span><span class="pln">questionNum</span><span class="pun">]]</span><span class="pln">
      </span><span class="pun">➋</span><span class="pln"> wrongAnswers </span><span class="pun">=</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">capitals</span><span class="pun">.</span><span class="pln">values</span><span class="pun">())</span><span class="pln">
      </span><span class="pun">➌</span><span class="pln"> </span><span class="kwd">del</span><span class="pln"> wrongAnswers</span><span class="pun">[</span><span class="pln">wrongAnswers</span><span class="pun">.</span><span class="pln">index</span><span class="pun">(</span><span class="pln">correctAnswer</span><span class="pun">)]</span><span class="pln">
      </span><span class="pun">➍</span><span class="pln"> wrongAnswers </span><span class="pun">=</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">sample</span><span class="pun">(</span><span class="pln">wrongAnswers</span><span class="pun">,</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"> answerOptions </span><span class="pun">=</span><span class="pln"> wrongAnswers </span><span class="pun">+</span><span class="pln"> </span><span class="pun">[</span><span class="pln">correctAnswer</span><span class="pun">]</span><span class="pln">
      </span><span class="pun">➏</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">shuffle</span><span class="pun">(</span><span class="pln">answerOptions</span><span class="pun">)</span><span class="pln">

         </span><span class="com"># TODO: كتابة السؤال والإجابات إلى ملف الاختبار</span><span class="pln">

         </span><span class="com"># TODO: كتابة مفتاح الحل إلى ملف الحلول.</span></pre>

<p>
	من السهل الحصول على الجواب الصحيحة، فهو القيمة المخزنة في القاموس <code>capitals</code> ➊. ستمر حلقة التكرار على جميع الولايات الموجودة ضمن قائمة <code>states</code> المرتبة عشوائيًا، من <code>states[0]‎</code> حتى <code>states[49]‎</code>، ويجد كل ولاية في <code>capitals</code> ثم يخزن الجواب الصحيح في المتغير <code>correctAnswer</code>.
</p>

<p>
	عملية إنشاء قائمة بالإجابات الخطأ أصعب بقليل، عليك أولًا أن تنسخ جميع القيم في قاموس <code>capitals</code> ➋، ثم تحذف الجواب الصحيح ➌، ثم تأخذ ثلاث قيم عشوائية من القائمة ➍؛ وتسهل علينا الدالة random.sample()<code>‎</code> ذلك، وتأخذ وسيطين: الأول هو القائمة التي تريد الاختيار منها، والثاني هو عدد القيم التي تريدها.
</p>

<p>
	ستكون القائمة النهائية هي الإضافة الصحيحة إضافةً إلى إجابات خطأ ثلاثة ➎، ثم علينا جعل الإجابات عشوائية ➏ كيلا تكون الإجابة D هي الإجابة الصحيحة دومًا.
</p>

<h3 id="4">
	الخطوة 4: كتابة المحتوى إلى ملفات الاختبارات والإجابات الصحيحة
</h3>

<p>
	كل ما بقي فعله هو كتابة السؤال إلى ملف الاختبار، وكتابة الإجابة إلى ملف الإجابات الصحيحة.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_105" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># randomQuizGenerator.py - إنشاء اختبارات مع أسئلة وإجابات عشوائية</span><span class="pln">
</span><span class="com"># مع تخزين مفتاح الحل.</span><span class="pln">

</span><span class="pun">--</span><span class="pln">snip</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"> questionNum </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">50</span><span class="pun">):</span><span class="pln">

    </span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">

        </span><span class="com"># كتابة السؤال والإجابات إلى ملف الاختبار.</span><span class="pln">
        quizFile</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">f</span><span class="str">'{questionNum + 1}. What is the capital of
{states[questionNum]}?\n'</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"> i </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">4</span><span class="pun">):</span><span class="pln">
          </span><span class="pun">➋</span><span class="pln"> quizFile</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">f</span><span class="str">"    {'ABCD'[i]}. { answerOptions[i]}\n"</span><span class="pun">)</span><span class="pln">
         quizFile</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">'\n'</span><span class="pun">)</span><span class="pln">

         </span><span class="com"># كتابة مفتاح الحل إلى ملف الحلول.</span><span class="pln">
      </span><span class="pun">➌</span><span class="pln"> answerKeyFile</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">f</span><span class="str">"{questionNum + 1}.
{'ABCD'[answerOptions.index(correctAnswer)]}"</span><span class="pun">)</span><span class="pln">
     quizFile</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span><span class="pln">
     answerKeyFile</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	تمر حلقة <code>for</code> على الأعداد 0 إلى 3 وتكتب الجواب في القائمة <code>answerOptions</code> ➊، أما التعبير <code>‎'ABCD'[i]‎</code> في ➋ أن السلسلة النصية <code>'ABCD'</code> ستعامل كمصفوفة وستكون قيمها هي 'A' ثم 'B' ثم 'C' ثم 'D' وفقًا لدورة حلقة التكرار.
</p>

<p>
	في السطر الأخير ➌ سيعثر التعبير answerOptions.index(correctAnswer)<code>‎</code> على فهرس الإجابة الصحيحة في قائمة الإجابات المعشوائية، ثم ستكون نتيجة التعبير البرمجي <code>‎'ABCD'[answerOptions.index(correctAnswer)]‎</code> هي حرف الجواب الصحيح الذي سيكتب في ملف الإجابات.
</p>

<p>
	بعد أن تشغل البرنامج فسيبدو الملف <code>capitalsquiz1.txt</code> كما يلي، مع الانتباه إلى أن الناتج سيكون مختلفًا عما عندك لأننا نأخذ القيم عشوائيًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_107" style=""><span class="typ">Name</span><span class="pun">:</span><span class="pln">

</span><span class="typ">Date</span><span class="pun">:</span><span class="pln">

</span><span class="typ">Period</span><span class="pun">:</span><span class="pln">

                    </span><span class="typ">State</span><span class="pln"> </span><span class="typ">Capitals</span><span class="pln"> </span><span class="typ">Quiz</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Form</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">

</span><span class="lit">1.</span><span class="pln"> </span><span class="typ">What</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> the capital of </span><span class="typ">West</span><span class="pln"> </span><span class="typ">Virginia</span><span class="pun">?</span><span class="pln">
    A</span><span class="pun">.</span><span class="pln"> </span><span class="typ">Hartford</span><span class="pln">
    B</span><span class="pun">.</span><span class="pln"> </span><span class="typ">Santa</span><span class="pln"> </span><span class="typ">Fe</span><span class="pln">
    C</span><span class="pun">.</span><span class="pln"> </span><span class="typ">Harrisburg</span><span class="pln">
    D</span><span class="pun">.</span><span class="pln"> </span><span class="typ">Charleston</span><span class="pln">

</span><span class="lit">2.</span><span class="pln"> </span><span class="typ">What</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> the capital of </span><span class="typ">Colorado</span><span class="pun">?</span><span class="pln">
    A</span><span class="pun">.</span><span class="pln"> </span><span class="typ">Raleigh</span><span class="pln">
    B</span><span class="pun">.</span><span class="pln"> </span><span class="typ">Harrisburg</span><span class="pln">
    C</span><span class="pun">.</span><span class="pln"> </span><span class="typ">Denver</span><span class="pln">
    D</span><span class="pun">.</span><span class="pln"> </span><span class="typ">Lincoln</span><span class="pln">

</span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span></pre>

<p>
	وسيبدو ملف capitalsquiz_answers1.txt كما يلي:
</p>

<pre class="ipsCode">1. D
2. C
3. A
4. C
--snip--
</pre>

<h2 id="-14">
	مشروع: تحديث لمشروع الحافظة
</h2>

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

<p>
	سنسمي مشروعنا <code>mcb.pyw</code>، فاختصار <code>mcb</code> هو <code>multi-clipboard</code> أي الحافظة المتعددة، والامتداد <code>‎.pyw</code> يعني أن بايثون لن تظهر نافذة الطرفية حين تشغيل البرنامج (راجع المقال الأول من السلسلة لمزيد من التفاصيل).
</p>

<p>
	سيحفظ البرنامج المحتويات النصية للحافظة تحت كلمة مفتاحية معينة، فمثلًا لو شغلت <code>py mcb.pyw save spam</code> فستحفظ المحتويات الحالية للحافظة مع الكلمة المفتاحية <code>spam</code>، ويمكن إعادة تحميل النص إلى الحافظة مجددًا بتشغيل <code>py mcb.pyw spam</code>، وإذا نسي المستخدم ما الكلمات المفتاحية التي استخدمها فيمكنه تشغيل <code>py mcb.pyw list</code> لنسخ قائمة فيها جميع الكلمات المفتاحية إلى الحافظة.
</p>

<p>
	هذه هي آلية عمل المشروع:
</p>

<ol>
	<li>
		التحقق من الوسيط الممرر عبر سطر الأوامر
	</li>
	<li>
		إذا كان save فستحفظ محتويات الحافظة إلى الكلمة المفتاحية المرسلة
	</li>
	<li>
		إذا كان list فستنسخ جميع الكلمات المفتاحية إلى الحافظة
	</li>
	<li>
		خلاف ذلك، سينسخ النص المرتبط بالكلمة المفتاحية إلى الحافظة.
	</li>
</ol>

<p>
	هذا يعني أن على البرنامج:
</p>

<ul>
	<li>
		قراءة وسائط سطر الأوامر من <code>sys.argv</code>.
	</li>
	<li>
		القراءة والكتابة إلى الحافظة.
	</li>
	<li>
		حفظ وتحميل ملف <code>shelf</code>.
	</li>
</ul>

<p>
	إذا كنت تستخدم ويندوز، فيمكنك ببساطة تشغيل السكربت من نافذة Run بإنشاء ملف <code>mcb.bat</code> فيه المحتوى الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_110" style=""><span class="lit">@pyw</span><span class="pun">.</span><span class="pln">exe C</span><span class="pun">:</span><span class="pln">\Python34\mcb</span><span class="pun">.</span><span class="pln">pyw </span><span class="pun">%*</span></pre>

<h3 id="1-1">
	الخطوة 1: البنية الأساسية وضبط عملية الحفظ والتحميل
</h3>

<p>
	لنبدأ بكتابة الهيكل الأساسي للسكربت مع بعض التعليقات وضبط أساسي لعملية الحفظ والتحميل:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_112" style=""><span class="pln">   </span><span class="com">#! python3</span><span class="pln">
   </span><span class="com"># mcb.pyw - حفظ وتحميل نصوص إلى الحافظة.</span><span class="pln">
</span><span class="pun">➊</span><span class="pln"> </span><span class="com"># Usage: py.exe mcb.pyw save &lt;keyword&gt; - حفظ الحاوية إلى keyword.</span><span class="pln">
   </span><span class="com">#        py.exe mcb.pyw &lt;keyword&gt; -تحميل محتويات keyword إلى الحاوية.</span><span class="pln">
   </span><span class="com">#        py.exe mcb.pyw list - تحميل كل الكلمات المفتاحية إلى الحاوية.</span><span class="pln">

</span><span class="pun">➋</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> shelve</span><span class="pun">,</span><span class="pln"> pyperclip</span><span class="pun">,</span><span class="pln"> sys

</span><span class="pun">➌</span><span class="pln"> mcbShelf </span><span class="pun">=</span><span class="pln"> shelve</span><span class="pun">.</span><span class="pln">open</span><span class="pun">(</span><span class="str">'mcb'</span><span class="pun">)</span><span class="pln">

   </span><span class="com"># TODO: حفظ محتويات الحاوية.</span><span class="pln">

   </span><span class="com"># TODO: إظهار كل الكلمات المفتاحية والمحتوى.</span></pre>

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

<h3 id="2-1">
	الخطوة 2: حفظ محتويات الحافظة مع كلمة مفتاحية
</h3>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_114" style=""><span class="pln">   </span><span class="com">#! python3</span><span class="pln">
   </span><span class="com"># mcb.pyw - حفظ وتحميل نصوص إلى الحافظة.</span><span class="pln">

   </span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">

   </span><span class="com"># حفظ محتوى الحافظة.</span><span class="pln">
</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">sys</span><span class="pun">.</span><span class="pln">argv</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="kwd">and</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">lower</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">'save'</span><span class="pun">:</span><span class="pln">
         </span><span class="pun">➋</span><span class="pln"> mcbShelf</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">2</span><span class="pun">]]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> pyperclip</span><span class="pun">.</span><span class="pln">paste</span><span class="pun">()</span><span class="pln">
   </span><span class="kwd">elif</span><span class="pln"> len</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="pln"> </span><span class="pun">==</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="com"># TODO: تحميل المحتوى وعرض الكلمات المفتاحية.</span><span class="pln">

mcbShelf</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	إذا كان أول وسيط من وسائط سطر الأوامر (الذي يكون دومًا بالفهرس 1 من قائمة <code>sys.argv</code>) هو <code>'save'</code> ➊ فإن الوسيط الثاني هو الكلمة المفتاحية التي يجب حفظ محتويات الحافظة إليها، والتي ستستخدم كمفتاح مع <code>mvbShelf</code>، وستكون قيمة هذا المفتاح هي محتويات الحافظة الحالية ➋.
</p>

<p>
	أما إذا كان هنالك وسيط واحد ممرر من سطر الأوامر فهذا يعني أنه إما <code>'list'</code> أو كلمة مفتاحية نريد تحميل المحتوى النصي المرتبط بها إلى الحافظة. اترك تعليقًا الآن وسنكتب الشيفرة لاحقًا ➌.
</p>

<h3 id="3-1">
	الخطوة 3: تحميل الكلمات المفتاحية أو محتوى إحدى الكلمات
</h3>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_116" style=""><span class="pln">   </span><span class="com">#! python3</span><span class="pln">
   </span><span class="com"># mcb.pyw - حفظ وتحميل نصوص إلى الحافظة.</span><span class="pln">

   </span><span class="pun">--</span><span class="pln">snip</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"> len</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="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="kwd">and</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">lower</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">'save'</span><span class="pun">:</span><span class="pln">
         mcbShelf</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">2</span><span class="pun">]]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> pyperclip</span><span class="pun">.</span><span class="pln">paste</span><span class="pun">()</span><span class="pln">
   </span><span class="kwd">elif</span><span class="pln"> len</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="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
   </span><span class="com"># تحميل المحتوى وعرض الكلمات المفتاحية.</span><span class="pln">
  </span><span class="pun">➊</span><span class="pln"> </span><span class="kwd">if</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">lower</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">'list'</span><span class="pun">:</span><span class="pln">
      </span><span class="pun">➋</span><span class="pln"> pyperclip</span><span class="pun">.</span><span class="pln">copy</span><span class="pun">(</span><span class="pln">str</span><span class="pun">(</span><span class="pln">list</span><span class="pun">(</span><span class="pln">mcbShelf</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">())))</span><span class="pln">
     </span><span class="kwd">elif</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="kwd">in</span><span class="pln"> mcbShelf</span><span class="pun">:</span><span class="pln">
      </span><span class="pun">➌</span><span class="pln"> pyperclip</span><span class="pun">.</span><span class="pln">copy</span><span class="pun">(</span><span class="pln">mcbShelf</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">

mcbShelf</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	إذا كان هنالك وسيط واحد في سطر الأوامر، فلنتأكد إن كان <code>'list'</code> ➊، فإذا كان كذلك فستنسخ سلسلة نصية تمثل قائمةً من الكلمات المفتاحية إلى الحافظة ➋، ويمكن للمستخدم أن يلصقها في أي محرر نصي أمامه ليقرأها.
</p>

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

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

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

<h2 id="-15">
	الخلاصة
</h2>

<p>
	تنظم الملفات في مجلدات (التي تسمى في بعض أنظمة التشغيل directory أي دليل)، ويصف مسارُ موقعَ الملف، ولكل برنامج يعمل في حاسوبك ما يسمى بمجلد العمل الحالي، مما يسمح بتحديد مسارات نسبية تبدأ من المجلد الحالي بدلًا من كتابة المسار الكامل للملف الذي يسمى أيضًا بالمسار المطلق. توفر الوحدتان <code>pathlib</code> و <code>os.path</code> عددًا من الدوال لإجراء عمليات على مسارات الملفات.
</p>

<p>
	يمكن أن تتفاعل برامجك مباشرةً مع محتويات الملفات النصية، فالدالة <code>open()‎</code> تفتح الملفات للقراءة، وتستطيع أن تحصل على محتواها كسلسلة نصية واحدة كبيرة عبر التابع <code>read()‎</code> أو كقائمة من السلاسل النصية عبر التابع <code>readlines()‎</code>. يمكن أن تستخدم الدالة open()<code>‎</code> لفتح الملفات في وضع الكتابة أو الإضافة لإنشاء ملفات نصية جديدة أو الإضافة على ملفات موجودة مسبقًا، على التوالي.
</p>

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

<h2 id="-16">
	مشاريع تدريبية
</h2>

<p>
	لكي تتدرب، اكتب برامج لتنفيذ المهام الآتية.
</p>

<h3 id="-17">
	توسعة تطبيق الحافظة
</h3>

<p>
	وسِّع تطبيق الحافظة الذي أنشأناه في هذا المقال وأضف إليه الأمر delete <keyword><code>‎</code> الذي يحذف كلمة مفتاحية ومحتوياتها من «الرف». ثم أضف الأمر <code>delete</code> دون أي وسائط إضافية الذي سيؤدي إلى حذف جميع الكلمات المفتاحية.</keyword>
</p>

<h3 id="madlibs">
	لعبة Mad Libs
</h3>

<p>
	أنشِئ لعبة Mad Libs التي تقرأ ملفًا نصية وتسمح للمستخدم بإضافة النص الذي يريده في أي مكان تظهر فيه الكلمات المفتاحية ADJECTIVE و NOUN و ADVERB و VERB في الملف النصي. فمثلًا سيبدو الملف النصي كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_118" style=""><span class="typ">The</span><span class="pln"> ADJECTIVE panda walked to the NOUN </span><span class="kwd">and</span><span class="pln"> then VERB</span><span class="pun">.</span><span class="pln"> A nearby NOUN was
unaffected by these events</span><span class="pun">.</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_120" style=""><span class="typ">Enter</span><span class="pln"> an adjective</span><span class="pun">:</span><span class="pln">
silly
</span><span class="typ">Enter</span><span class="pln"> a noun</span><span class="pun">:</span><span class="pln">
chandelier
</span><span class="typ">Enter</span><span class="pln"> a verb</span><span class="pun">:</span><span class="pln">
screamed
</span><span class="typ">Enter</span><span class="pln"> a noun</span><span class="pun">:</span><span class="pln">
pickup truck</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1905_122" style=""><span class="typ">The</span><span class="pln"> silly panda walked to the chandelier </span><span class="kwd">and</span><span class="pln"> then screamed</span><span class="pun">.</span><span class="pln"> A nearby pickup
truck was unaffected by these events</span><span class="pun">.</span></pre>

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

<h3 id="-18">
	البحث عبر التعابير النمطية
</h3>

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

<p>
	ترجمة -بتصرف- للمقال <a href="https://automatetheboringstuff.com/2e/chapter9/" rel="external nofollow">Reading And Writing Files</a> من كتاب <a href="https://automatetheboringstuff.com/#toc" rel="external nofollow">Automate the Boring Stuff with Python</a>.
</p>

<h2 id="-19">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%AA%D8%AD%D9%82%D9%82-%D9%85%D9%86-%D8%A7%D9%84%D9%85%D8%AF%D8%AE%D9%84%D8%A7%D8%AA-%D8%B9%D8%A8%D8%B1-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2346/" rel="">التحقق من المدخلات عبر بايثون python</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-lists-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r2339/" rel="">القوائم Lists في لغة بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2322/" rel="">تهيئة بيئة العمل في بايثون Python</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2347</guid><pubDate>Thu, 27 Jun 2024 15:06:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x62D;&#x642;&#x642; &#x645;&#x646; &#x627;&#x644;&#x645;&#x62F;&#x62E;&#x644;&#x627;&#x62A; &#x639;&#x628;&#x631; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646; python</title><link>https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%AA%D8%AD%D9%82%D9%82-%D9%85%D9%86-%D8%A7%D9%84%D9%85%D8%AF%D8%AE%D9%84%D8%A7%D8%AA-%D8%B9%D8%A8%D8%B1-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2346/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_06/-----(1).png.5f861caff548e01db1923c421204d741.png" /></p>
<p>
	شيفرات التحقق من المدخلات تتأكد أن ما يدخله المستخدم، مثل النصوص الآتية من الدالة <code>()input</code>، هي مكتوبة كتابةً صحيحةً؛ فمثلًا حينما نطلب من المستخدمين إدخال أعمارهم، فلا يفترض أن يقبل برنامجك أجوبةً غير منطقية على السؤال، مثل الأرقام السالبة (التي هي خارج المجال المنطقي للأعمار) أو الكلمات (نوع البيانات خطأ).
</p>

<p>
	يمنع التحقق من المدخلات حدوث العلل والمشاكل الأمنية، فلو كانت لدينا دالة باسم <code>widthdrawFromAccount()‎</code> التي تأخذ وسيطًا هو المبلغ الذي يجب اقتطاعه من حساب المستخدم، فيجب علينا الحرص على أن يكون المبلغ قيمةً إيجابية، فلو لم نتحقق من ذلك ومررنا قيمةً سالبة إلى الدالة <code>widthdrawFromAccount()‎</code> وطرحت هذه الدالة القيمة السالبة من حسابنا فسنحصل على أموال بدل سحبها!
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_8" style=""><span class="kwd">while</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Enter your age:'</span><span class="pun">)</span><span class="pln">
    age </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
        age </span><span class="pun">=</span><span class="pln"> int</span><span class="pun">(</span><span class="pln">age</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="str">'Please use numeric digits.'</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">continue</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> age </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Please enter a positive number.'</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">continue</span><span class="pln">
    </span><span class="typ">Break</span><span class="pln">

</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">f</span><span class="str">'Your age is {age}.'</span><span class="pun">)</span></pre>

<p>
	إذا شغلنا هذا البرنامج فسيكون الناتج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_10" style=""><span class="typ">Enter</span><span class="pln"> your age</span><span class="pun">:</span><span class="pln">
five
</span><span class="typ">Please</span><span class="pln"> use numeric digits</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> your age</span><span class="pun">:</span><span class="pln">
</span><span class="pun">-</span><span class="lit">2</span><span class="pln">
</span><span class="typ">Please</span><span class="pln"> enter a positive number</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> your age</span><span class="pun">:</span><span class="pln">
</span><span class="lit">30</span><span class="pln">
</span><span class="typ">Your</span><span class="pln"> age </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">30.</span></pre>

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

<p>
	لكن كتابة شيفرات للتحقق لكل استدعاء للدالة <code>input()‎</code> في برنامجك هو أمر ممل وصعب، ومن المرجح أنك ستغفل عن بعض الحالت مما يؤدي إلى مرور مدخلات خطأ إلى برنامجك. لذا سنتعلم كيف نستعمل الوحدة <code>PyInputPlus</code> في هذا المقال للتحقق من المدخلات.
</p>

<h2 id="pyinputplus">
	الوحدة PyInputPlus
</h2>

<p>
	تحتوي الوحدة <code>PyInputPlus</code> على عدد من الدوال الشبيه بالدالة <code>input()‎</code> لعدد من أنواع البيانات: الأرقام، والتواريخ، وعناوين البريد الإلكتروني، والمزيد.
</p>

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

<p>
	الوحدة <code>PyInputPlus</code> ليست جزءًا من المكتبة القياسية في <a href="https://wiki.hsoub.com/Python" rel="external">بايثون</a>، لذا يجب عليك تثبيتها بشكل منفصل عبر استخدام مدير الحزم pip؛ وذلك بتشغيل الأمر <code>pip install --user pyinputplus</code> من <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%A7-%D9%87%D9%88-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%9F-r353/" rel="">سطر الأوامر</a>. يشرح <a href="https://academy.hsoub.com/programming/python/%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2322/" rel="">المقال الأول من السلسلة</a> بالتفصيل خطوات تثبيت الوحدات الخارجية. للتحقق من سلامة تثبيت الوحدة <code>PyInputPlus</code> يمكننا تجربة استيرادها في الطرفية التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_14" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> pyinputplus</span></pre>

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

<p>
	تمتلك الوحدة <code>PyInputPlus</code> عددًا من الدوال للتعامل مع مختلف أنواع المدخلات:
</p>

<ul>
	<li>
		<code>inputStr()‎</code> تشبه الدالة <code>input()‎</code> لكنها تمتلك ميزات وحدة <code>PyInputPlus</code> العامة، كما أن بإمكاننا تمرير دالة تحقق مخصصة.
	</li>
	<li>
		inputNum()<code>‎</code> تتحقق أن المستخدم يدخل رقمًا، وتعيد عددًا صحيحًا <code>int</code> أو عشريًا <code>float</code>، اعتمادًا إذا كان الرقم فيه فاصلة عشرية أم لا.
	</li>
	<li>
		inputChoice()<code>‎</code> تتحقق أن المستخدم اختار أحد الخيارات الموفرة له.
	</li>
	<li>
		<code>inputMenu()‎</code> شبيهة بالدالة <code>inputChoice()‎</code> لكنها توفر قائمة مع خيارات لها أرقام أو أحرف.
	</li>
	<li>
		inputDatetime()<code>‎</code> تتحقق أن المستخدم أدخل تاريخًا ووقتًا.
	</li>
	<li>
		inputYesNo()<code>‎</code> تتحقق أن المستخدم أدخل yes أو no. inputBool()<code>*‎</code> تشبه الدالة <code>inputYesNo()‎</code> لكنها تقبل القيمة <code>True</code> أو <code>False</code> وتعيد <a href="https://wiki.hsoub.com/Python/boolean" rel="external">قيمة منطقية</a>.
	</li>
	<li>
		inputEmail()<code>‎</code> تتحقق أن المستخدم أدخل بريدًا إلكترونيًا صالحًا.
	</li>
	<li>
		inputFilepath()<code>‎</code> تتأكد أن المستخدم أدخل مسارًا صالحًا لأحد الملفات، ويمكن أن تتحقق اختيارًا أن هنالك ملف بهذا الاسم.
	</li>
	<li>
		<code>inputPassword()‎</code> كما في الدالة المبنية في بايثون <code>input()‎</code> لكنها تظهر نجومًا <code>*</code> بدل إظهار مدخلات المستخدم لكي لا تظهر المدخلات الحساسة مثل كلمات المرور على الشاشة.
	</li>
</ul>

<p>
	ستعيد هذه <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2336/" rel="">الدوال</a> طلب إدخال مدخلات صالحة من المستخدم في حال أدخل قيمةً خطأ:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_16" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> pyinputplus </span><span class="kwd">as</span><span class="pln"> pyip
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> pyip</span><span class="pun">.</span><span class="pln">inputNum</span><span class="pun">()</span><span class="pln">
five
</span><span class="str">'five'</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> a number</span><span class="pun">.</span><span class="pln">
</span><span class="lit">42</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response
</span><span class="lit">42</span></pre>

<p>
	كتابة <code>as pyip</code> في عبارة <code>import</code> توفر علينا وقتًا في كتابة <code>pyinputplus</code> في كل مرة نريد استدعاء دالة من الوحدة <code>PyInputPlus</code>، وسنكتب بدلًا منها <code>pyip</code>.
</p>

<p>
	إذا نظرت إلى المثال السابق فستجد أن الدوال تعيد القيمة <code>int</code> أو <code>float</code> على عكس input()<code>‎</code> التي تعيد سلاسل نصية مثل '42'.
</p>

<p>
	وكما كنا نمرر سلسلة نصية إلى <code>input()‎</code> لاستعمالها كمحث prompt، فيمكننا تمرير سلسلة نصية إلى دوال <code>PyInputPlus</code> عبر استخدام الوسائط ذات الكلمات المفتاحية Keyword arguments، واستخدام الوسيط prompt لعرض المحث:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_18" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">'Enter a number: '</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> a number</span><span class="pun">:</span><span class="pln"> </span><span class="lit">42</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response
</span><span class="str">'42'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> pyinputplus </span><span class="kwd">as</span><span class="pln"> pyip
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> pyip</span><span class="pun">.</span><span class="pln">inputInt</span><span class="pun">(</span><span class="pln">prompt</span><span class="pun">=</span><span class="str">'Enter a number: '</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> a number</span><span class="pun">:</span><span class="pln"> cat
</span><span class="str">'cat'</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> an integer</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> a number</span><span class="pun">:</span><span class="pln"> </span><span class="lit">42</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response
</span><span class="lit">42</span></pre>

<p>
	يمكنك استخدام الدالة <code>help()‎</code> في بايثون لتعرف المزيد من المعلومات حول أي دالة من تلك الدوال، فمثلًا كتابة <code>help(pyip.inputChoice)‎</code> سيعرض معلومات حول الدالة <code>inputChoice()‎</code>. يمكنك أن تقرأ التوثيق كاملًا عبر <a href="https://pyinputplus.readthedocs.io" rel="external nofollow">pyinputplus.readthedocs</a>. على خلاف الدالة المبنية في بايثون <code>input()‎</code>، تمتلك دوال الوحدة <code>PyInputPlus</code> عددًا من الميزات الإضافية للتحقق من المدخلات، كما سنشرح في القسم التالي.
</p>

<h3 id="minmaxgreaterthanlessthan">
	وسائط ذات الكلمات المفتاحية min و max و greaterThan و lessThan
</h3>

<p>
	تمتلك الدوال <code>inputNum()‎</code> و <code>inputInt()‎</code> و inputFloat()<code>‎</code> التي تقبل <a href="https://wiki.hsoub.com/Python/int" rel="external">الأرقام الصحيحة int</a> و<a href="https://wiki.hsoub.com/Python/float" rel="external">العشرية float</a> الوسائط ذات الكلمات المفتاحية <code>min</code> و <code>max</code> و <code>greaterThan</code> و <code>lessThan</code> لتحديد مجال من القيم الصالحة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_20" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> pyinputplus </span><span class="kwd">as</span><span class="pln"> pyip
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> pyip</span><span class="pun">.</span><span class="pln">inputNum</span><span class="pun">(</span><span class="str">'Enter num: '</span><span class="pun">,</span><span class="pln"> min</span><span class="pun">=</span><span class="lit">4</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> num</span><span class="pun">:</span><span class="lit">3</span><span class="pln">
</span><span class="typ">Input</span><span class="pln"> must be at minimum </span><span class="lit">4.</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> num</span><span class="pun">:</span><span class="lit">4</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response
</span><span class="lit">4</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> pyip</span><span class="pun">.</span><span class="pln">inputNum</span><span class="pun">(</span><span class="str">'Enter num: '</span><span class="pun">,</span><span class="pln"> greaterThan</span><span class="pun">=</span><span class="lit">4</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> num</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pln">
</span><span class="typ">Input</span><span class="pln"> must be greater than </span><span class="lit">4.</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> num</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response
</span><span class="lit">5</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> pyip</span><span class="pun">.</span><span class="pln">inputNum</span><span class="pun">(</span><span class="str">'&gt;'</span><span class="pun">,</span><span class="pln"> min</span><span class="pun">=</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> lessThan</span><span class="pun">=</span><span class="lit">6</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> num</span><span class="pun">:</span><span class="pln"> </span><span class="lit">6</span><span class="pln">
</span><span class="typ">Input</span><span class="pln"> must be less than </span><span class="lit">6.</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> num</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
</span><span class="typ">Input</span><span class="pln"> must be at minimum </span><span class="lit">4.</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> num</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"> response
</span><span class="lit">4</span></pre>

<p>
	هذه الوسائط ذات الكلمات المفتاحية هي اختيارية، لكن إذا ضبطناها فلا يمكن أن تكون مدخلات المستخدم أقل من min أو أكبر من max (لكن يمكن أن تكون المدخلات مساويةً لها)؛ ويجب أن تكون المدخلات أيضًا أكبر من قيمة <code>greaterThan</code> وأقل من قيمة <code>lessThan</code> (وأيضًا يمكن أن تكون المدخلات مساويةً لها).
</p>

<h3 id="blank">
	الوسيط ذو الكلمة المفتاحية blank
</h3>

<p>
	افتراضيًا لا يُسمَح بالقيم الفارغة ما لم يضبط الوسيط <code>blank</code> إلى <code>True</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_22" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> pyinputplus </span><span class="kwd">as</span><span class="pln"> pyip
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> pyip</span><span class="pun">.</span><span class="pln">inputNum</span><span class="pun">(</span><span class="str">'Enter num: '</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> num</span><span class="pun">:(</span><span class="pln">blank input entered here</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Blank</span><span class="pln"> values are </span><span class="kwd">not</span><span class="pln"> allowed</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> num</span><span class="pun">:</span><span class="pln"> </span><span class="lit">42</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response
</span><span class="lit">42</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> pyip</span><span class="pun">.</span><span class="pln">inputNum</span><span class="pun">(</span><span class="pln">blank</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">)</span><span class="pln">
</span><span class="pun">(</span><span class="pln">blank input entered here</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response
</span><span class="str">''</span></pre>

<p>
	استخدام <code>blank=True</code> إذا أردت أن تجعل مدخلات المستخدم اختيارية.
</p>

<h3 id="limittimeoutdefault">
	الوسائط ذات الكلمات المفتاحية limit و timeout و default
</h3>

<p>
	ستستمر دوال الوحدة <code>PyInputPlus</code> سؤال المستخدم عن مدخلات صالحة للأبد (ما دام البرنامج يعمل بالطبع) افتراضيًا. لكن إذا أردنا أن تتوقف الدالة عن سؤال المستخدم بعد عدد من المحاولات أو بعد وقتٍ محدد، فيمكننا استخدام الوسيط <code>limit</code> و <code>timeout</code>.
</p>

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

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_24" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> pyinputplus </span><span class="kwd">as</span><span class="pln"> pyip
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> pyip</span><span class="pun">.</span><span class="pln">inputNum</span><span class="pun">(</span><span class="pln">limit</span><span class="pun">=</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
blah
</span><span class="str">'blah'</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> a number</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> num</span><span class="pun">:</span><span class="pln"> number
</span><span class="str">'number'</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> a number</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
    </span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">
pyinputplus</span><span class="pun">.</span><span class="typ">RetryLimitException</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> pyip</span><span class="pun">.</span><span class="pln">inputNum</span><span class="pun">(</span><span class="pln">timeout</span><span class="pun">=</span><span class="lit">10</span><span class="pun">)</span><span class="pln">
</span><span class="lit">42</span><span class="pln"> </span><span class="pun">(</span><span class="pln">entered after </span><span class="lit">10</span><span class="pln"> seconds of waiting</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
    </span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">
pyinputplus</span><span class="pun">.</span><span class="typ">TimeoutException</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_26" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> pyip</span><span class="pun">.</span><span class="pln">inputNum</span><span class="pun">(</span><span class="pln">limit</span><span class="pun">=</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> default</span><span class="pun">=</span><span class="str">'N/A'</span><span class="pun">)</span><span class="pln">
hello
</span><span class="str">'hello'</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> a number</span><span class="pun">.</span><span class="pln">
world
</span><span class="str">'world'</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> a number</span><span class="pun">.</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response
</span><span class="str">'N/A'</span></pre>

<p>
	فبدلًا من رمي الاستثناء <code>RetryLimitException</code> فستعيد الدالة <code>inputNum()‎</code> السلسلة النصية <code>'N/A'</code>.
</p>

<h3 id="allowregexesblockregexes">
	الوسيط ذو الكلمة المفتاحية allowRegexes و blockRegexes
</h3>

<p>
	يمكنك استخدام <a href="https://academy.hsoub.com/programming/python/%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-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2345/" rel="">التعابير النمطية</a> للتحقق إن كانت المدخلات مسموحٌ بها أم لا. فالوسيطان <code>allowRegexes</code> و <code>blockRegexes</code> يأخذها قائمةً من التعابير النمطية لتحديد إن كانت دالة <code>PyInputPlus</code> ستسمح بالمدخلات على أنها مقبولة أو ترفضها. جرب مثلًا الشيفرة الآتية في الطرفية التفاعلية لكي تقبل الدالة <code>inputNum()‎</code> الأرقام الرومانية بالإضافة إلى الأرقام العادية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_28" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> pyinputplus </span><span class="kwd">as</span><span class="pln"> pyip
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> pyip</span><span class="pun">.</span><span class="pln">inputNum</span><span class="pun">(</span><span class="pln">allowRegexes</span><span class="pun">=[</span><span class="pln">r</span><span class="str">'(I|V|X|L|C|D|M)+'</span><span class="pun">,</span><span class="pln"> r</span><span class="str">'zero'</span><span class="pun">])</span><span class="pln">
XLII
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response
</span><span class="str">'XLII'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> pyip</span><span class="pun">.</span><span class="pln">inputNum</span><span class="pun">(</span><span class="pln">allowRegexes</span><span class="pun">=[</span><span class="pln">r</span><span class="str">'(i|v|x|l|c|d|m)+'</span><span class="pun">,</span><span class="pln"> r</span><span class="str">'zero'</span><span class="pun">])</span><span class="pln">
xlii
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response
</span><span class="str">'xlii'</span></pre>

<p>
	ما سيؤثر عليه هذا <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> هو الأحرف التي ستقبلها الدالة <code>inputNum()‎</code> من المستخدم، فالدالة حاليًا تقبل الأرقام الرومانية ذات الترتيب الخطأ مثل 'XVX' أو 'MILLI' لأن التعبير النمطي r'(I|V|X|L|C|D|M)+'‎ يقبل هذه القيم.
</p>

<p>
	يمكنك أيضًا تحديد قائمة بالتعابير النمطية التي سترفضها دالة <code>PyInputPlus</code> باستخدام الوسيط <code>blockRegexes</code>. جرب المثال الآتي في الطرفية التفاعلية لترى أن الدالة <code>inputNum()‎</code> لن تقبل الأرقام الزوجية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_30" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> pyinputplus </span><span class="kwd">as</span><span class="pln"> pyip
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> pyip</span><span class="pun">.</span><span class="pln">inputNum</span><span class="pun">(</span><span class="pln">blockRegexes</span><span class="pun">=[</span><span class="pln">r</span><span class="str">'[02468]$'</span><span class="pun">])</span><span class="pln">
</span><span class="lit">42</span><span class="pln">
</span><span class="typ">This</span><span class="pln"> response </span><span class="kwd">is</span><span class="pln"> invalid</span><span class="pun">.</span><span class="pln">
</span><span class="lit">44</span><span class="pln">
</span><span class="typ">This</span><span class="pln"> response </span><span class="kwd">is</span><span class="pln"> invalid</span><span class="pun">.</span><span class="pln">
</span><span class="lit">43</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response
</span><span class="lit">43</span></pre>

<p>
	إذا حددت قيمتين للوسيطين <code>allowRegexes</code> و <code>blockRegexes</code>، فإن قائمة السماح ستأخذ أولوية على قائمة الرفض؛ جرب المثال الآتي الذي يسمح بالكلمتين 'caterpillar' و 'category' لكنه يرفض أي مدخلات فيها الكلمة 'cat'`:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_32" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> pyinputplus </span><span class="kwd">as</span><span class="pln"> pyip
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> pyip</span><span class="pun">.</span><span class="pln">inputStr</span><span class="pun">(</span><span class="pln">allowRegexes</span><span class="pun">=[</span><span class="pln">r</span><span class="str">'caterpillar'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'category'</span><span class="pun">],</span><span class="pln">
blockRegexes</span><span class="pun">=[</span><span class="pln">r</span><span class="str">'cat'</span><span class="pun">])</span><span class="pln">
cat
</span><span class="typ">This</span><span class="pln"> response </span><span class="kwd">is</span><span class="pln"> invalid</span><span class="pun">.</span><span class="pln">
catastrophe
</span><span class="typ">This</span><span class="pln"> response </span><span class="kwd">is</span><span class="pln"> invalid</span><span class="pun">.</span><span class="pln">
category
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response
</span><span class="str">'category'</span></pre>

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

<h3 id="inputcustom">
	تمرير دالة تحقق خاصة إلى inputCustom()‎
</h3>

<p>
	يمكننا كتابة دالة خاصة بنا لتجري عملية التحقق، ونمررها إلى الدالة inputCustom()<code>‎</code>. لنقل مثلًا أننا نريد من المستخدم أن يدخل سلسلةً من الأرقام التي يجب أن يكون مجموعها 10؛ فلن نجد دالةً باسم <code>pyinputplus.inputAddsUpToTen()‎</code> لكننا نستطيع إنشاء دالة خاصة بنا التي:
</p>

<ul>
	<li>
		تقبل معاملًا واحدًا هو السلسلة النصية التي أدخلها المستخدم.
	</li>
	<li>
		ترمي استثناءً حين وقوع مشكلة في التحقق.
	</li>
	<li>
		تعيد None (أو لا تحتوي على عبارة return) إذا أردنا أن تعيد الدالة <code>inputCustom()‎</code> مدخلات المستخدم كما هي.
	</li>
	<li>
		تعيد قيمة ليست None إذا أردنا أن تعيد الدالة <code>inputCustom()‎</code> سلسلةً نصيةً مختلفةً عمّا أدخله المستخدم.
	</li>
	<li>
		نمررها كأول وسيط إلى الدالة <code>inputCustom()‎</code>.
	</li>
</ul>

<p>
	سننشِئ في هذا المثال الدالة addsUpToTen()<code>‎</code> الخاصة بنا ومررناها إلى الدالة <code>inputCustom()‎</code>. لاحظ أن استدعاء الدالة يكون على الشكل <code>inputCustom(addsUpToTen)‎</code> وليس <code>inputCustom(addsUpToTen())‎</code> لأننا نريد تمرير الدالة addsUpToTen()<code>‎</code> نفسها إلى الدالة <code>inputCustom()‎</code>، وليس استدعاء الدالة <code>addsUpToTen()‎</code> وتمرير القيمة المعادة منها.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_34" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> pyinputplus </span><span class="kwd">as</span><span class="pln"> pyip
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">def</span><span class="pln"> addsUpToTen</span><span class="pun">(</span><span class="pln">numbers</span><span class="pun">):</span><span class="pln">
</span><span class="pun">...</span><span class="pln">   numbersList </span><span class="pun">=</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">numbers</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"> i</span><span class="pun">,</span><span class="pln"> digit </span><span class="kwd">in</span><span class="pln"> enumerate</span><span class="pun">(</span><span class="pln">numbersList</span><span class="pun">):</span><span class="pln">
</span><span class="pun">...</span><span class="pln">     numbersList</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"> int</span><span class="pun">(</span><span class="pln">digit</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"> sum</span><span class="pun">(</span><span class="pln">numbersList</span><span class="pun">)</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">10</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">Exception</span><span class="pun">(</span><span class="str">'The digits must add up to 10, not %s.'</span><span class="pln"> </span><span class="pun">%</span><span class="pln">
</span><span class="pun">(</span><span class="pln">sum</span><span class="pun">(</span><span class="pln">numbersList</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"> int</span><span class="pun">(</span><span class="pln">numbers</span><span class="pun">)</span><span class="pln"> </span><span class="com"># إعادة عدد صحيح</span><span class="pln">
</span><span class="pun">...</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> pyip</span><span class="pun">.</span><span class="pln">inputCustom</span><span class="pun">(</span><span class="pln">addsUpToTen</span><span class="pun">)</span><span class="pln"> </span><span class="com"># لا توجد أقواس بعد اسم الدالة</span><span class="pln">
</span><span class="lit">123</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> digits must add up to </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="lit">6.</span><span class="pln">
</span><span class="lit">1235</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> digits must add up to </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="lit">11.</span><span class="pln">
</span><span class="lit">1234</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response </span><span class="com"># inputStr() أعادت رقمًا وليس سلسلةً نصية</span><span class="pln">
</span><span class="lit">1234</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> pyip</span><span class="pun">.</span><span class="pln">inputCustom</span><span class="pun">(</span><span class="pln">addsUpToTen</span><span class="pun">)</span><span class="pln">
hello
invalid literal </span><span class="kwd">for</span><span class="pln"> int</span><span class="pun">()</span><span class="pln"> </span><span class="kwd">with</span><span class="pln"> base </span><span class="lit">10</span><span class="pun">:</span><span class="pln"> </span><span class="str">'h'</span><span class="pln">
</span><span class="lit">55</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> response</span></pre>

<p>
	الدالة <code>inputCustom()‎</code> تقبل أيضًا بقية ميزات <code>PyInputPlus</code> مثل <code>blank</code> و <code>limit</code> و<code> timeout</code> و<code> default </code>و<code> allowRegexes</code> و<code> blockRegexes</code>.
</p>

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

<h2 id="">
	مشروع: هل تريد معرفة حكمة اليوم؟
</h2>

<p>
	لنستخدم <code>PyInputPlus</code> لإنشاء مشروع بسيط يفعل ما يلي:
</p>

<ol>
	<li>
		يسأل المستخدم إن كان يريد معرفة حكمة اليوم؟
	</li>
	<li>
		إذا أدخل المستخدم no فسينتهي البرنامج بسلام
	</li>
	<li>
		إذا أدخل المستخدم yes فسيذهب إلى الخطوة 1.
	</li>
</ol>

<p>
	أجزم أنك لا تريد أن تعرف الحكمة من مثالنا <span class="ipsEmoji">?</span> .
</p>

<p>
	لا نعرف إن كان سيدخل المستخدم أي سلسلة نصية خلاف "yes" و "no" لذا علينا إجراء عملية تحقق من صحة المدخلات، وسيكون جميلًا أن نسمح للمستخدم بإدخال "y" أو "n" بدلًا من كتابة كاملة الكلمة. تستطيع الدالة <code>inputYesNo()‎</code> فعل ذلك، وستعيد لنا السلسلة النصية <code>'yes'</code> أو <code>'no'</code> بغض النظر عن طريقة الإيجاب أو الرفض التي استعملها المستخدم:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_36" style=""><span class="typ">Want</span><span class="pln"> to know how to keep a </span><span class="str">'wise'</span><span class="pln"> man busy </span><span class="kwd">for</span><span class="pln"> hours</span><span class="pun">?</span><span class="pln">
sure
</span><span class="str">'sure'</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> a valid yes</span><span class="pun">/</span><span class="pln">no response</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Want</span><span class="pln"> to know how to keep a </span><span class="str">'wise'</span><span class="pln"> man busy </span><span class="kwd">for</span><span class="pln"> hours</span><span class="pun">?</span><span class="pln">
yes
</span><span class="typ">Want</span><span class="pln"> to know how to keep a </span><span class="str">'wise'</span><span class="pln"> man busy </span><span class="kwd">for</span><span class="pln"> hours</span><span class="pun">?</span><span class="pln">
y
</span><span class="typ">Want</span><span class="pln"> to know how to keep a </span><span class="str">'wise'</span><span class="pln"> man busy </span><span class="kwd">for</span><span class="pln"> hours</span><span class="pun">?</span><span class="pln">
</span><span class="typ">Yes</span><span class="pln">
</span><span class="typ">Want</span><span class="pln"> to know how to keep a </span><span class="str">'wise'</span><span class="pln"> man busy </span><span class="kwd">for</span><span class="pln"> hours</span><span class="pun">?</span><span class="pln">
YES
</span><span class="typ">Want</span><span class="pln"> to know how to keep a </span><span class="str">'wise'</span><span class="pln"> man busy </span><span class="kwd">for</span><span class="pln"> hours</span><span class="pun">?</span><span class="pln">
YES</span><span class="pun">!!!!!!</span><span class="pln">
</span><span class="str">'YES!!!!!!'</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> a valid yes</span><span class="pun">/</span><span class="pln">no response</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Want</span><span class="pln"> to know how to keep a </span><span class="str">'wise'</span><span class="pln"> man busy </span><span class="kwd">for</span><span class="pln"> hours</span><span class="pun">?</span><span class="pln">
TELL ME HOW TO KEEP A WISE MAN BUSY FOR HOURS</span><span class="pun">.</span><span class="pln">
</span><span class="str">'TELL ME HOW TO KEEP A WISE MAN BUSY FOR HOURS.'</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> a valid yes</span><span class="pun">/</span><span class="pln">no response</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Want</span><span class="pln"> to know how to keep a </span><span class="str">'wise'</span><span class="pln"> man busy </span><span class="kwd">for</span><span class="pln"> hours</span><span class="pun">?</span><span class="pln">
no
</span><span class="typ">Thank</span><span class="pln"> you</span><span class="pun">.</span><span class="pln"> </span><span class="typ">Have</span><span class="pln"> a nice day</span><span class="pun">.</span></pre>

<p>
	افتح محرر النصوص وسمِّ ملفك باسم <code>idiot.py</code> وأدخل ما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_38" style=""><span class="kwd">import</span><span class="pln"> pyinputplus </span><span class="kwd">as</span><span class="pln"> pyip</span></pre>

<p>
	سنستورد الوحدة <code>PyInputPlus</code>، لكننا نريد اختصار اسمها في برنامجنا إلى <code>pyip</code> لأنها أقصر من كتابة <code>pyinputplus</code> في كل مرة.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_40" style=""><span class="kwd">while</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">:</span><span class="pln">
    prompt </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Want to know how to keep a '</span><span class="pln">wise</span><span class="str">' man busy for hours?\n'</span><span class="pln">
    response </span><span class="pun">=</span><span class="pln"> pyip</span><span class="pun">.</span><span class="pln">inputYesNo</span><span class="pun">(</span><span class="pln">prompt</span><span class="pun">)</span></pre>

<p>
	ثم سندخل في حلقة تكرار لا نهائية لا تنتهي إلا بالخروج من البرنامج أو الوصول إلى <a href="https://wiki.hsoub.com/Python/for#.D8.B9.D8.A8.D8.A7.D8.B1.D8.AA.D8.A7_break_.D9.88_else" rel="external">عبارة break</a>. وسنستخدم الدالة <code>pyip.inputYesNo()‎</code> في هذه الحلقة لقبول مدخلات المستخدم والتحقق أنها yes أو no.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_42" style=""><span class="pln">    </span><span class="kwd">if</span><span class="pln"> response </span><span class="pun">==</span><span class="pln"> </span><span class="str">'no'</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">break</span></pre>

<p>
	الدالة pyip.inputYesNo()<code>‎</code> مصممة لتعيد السلسلة النصية yes أو no؛ فإذا أعادت no فسنخرج من الحلقة اللانهائية ونكمل تنفيذ السطر الأخير من البرنامج الذي يشكر المستخدم على صبره:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_44" style=""><span class="kwd">print</span><span class="pun">(</span><span class="str">'Thank you. Have a nice day.'</span><span class="pun">)</span></pre>

<p>
	وإلا فسيستمر تنفيذ حلقة التكرار.
</p>

<p>
	يمكنك إنشاء نسخة من الدالة <code>inputYesNo()‎</code> في اللغات غير الإنكليزية بتمرير قيم للوسيطين ذوي الكلمات المفتاحية <code>yesVal</code> و <code>noVal</code>. فانظر إلى المثال الآتي باللغة الإسبانية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_46" style=""><span class="pln">   prompt </span><span class="pun">=</span><span class="pln"> </span><span class="str">'¿Quieres saber cómo mantener ocupado a un idiota durante horas?\n'</span><span class="pln">
    response </span><span class="pun">=</span><span class="pln"> pyip</span><span class="pun">.</span><span class="pln">inputYesNo</span><span class="pun">(</span><span class="pln">prompt</span><span class="pun">,</span><span class="pln"> yesVal</span><span class="pun">=</span><span class="str">'sí'</span><span class="pun">,</span><span class="pln"> noVal</span><span class="pun">=</span><span class="str">'no'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> response </span><span class="pun">==</span><span class="pln"> </span><span class="str">'sí'</span><span class="pun">:</span></pre>

<p>
	يمكن للمستخدم الآن إدخال <code>sí</code> أو <code>s</code> (سواءً كانت بأحرف كبيرة أو صغيرة) بدلًا من yes أو y للإيجاب بالموافقة.
</p>

<h2 id="-1">
	مشروع: اختبار جدول الضرب
</h2>

<p>
	يمكننا استخدام ميزات الوحدة <code>PyInputPlus</code> لإنشاء اختبار لجدول الضرب له وقت معين. إذ نستطيع أن نضبط قيم للوسائط ذات الكلمات المفتاحية <code>allowRegexes</code> و <code>blockRegexes</code> و <code>timeout</code> و <code>limit</code> للدالة <code>pyip.inputStr()‎</code> ونترك أمر التحقق من صحة مدخلات المستخدم على الوحدة <code>PyInputPlus</code>.
</p>

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

<p>
	لننشِئ برنامجًا يعرض 10 أسئلة في جدول الضرب على المستخدم، ولا يجوز أن يدخل المستخدم سوى الأرقام الصحيحة. احفظ الشيفرات الآتية في ملف باسم <code>multiplicationQuiz.py</code>.
</p>

<p>
	سنستورد في البداية الوحدات <code>pyinputplus</code> و <code>random</code> و <code>time</code>. وسنتتبع عدد الأسئلة التي يسألها برنامجنا وعدد الإجابات الصحيحة التي يوفرها المستخدم عبر المتغيرين <code>numberOfQuestions</code> و <code>correctAnswers</code>. سنسأل المستخدم داخل <a href="https://wiki.hsoub.com/Python/for" rel="external">حلقة for</a> لعشر مرات.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_48" style=""><span class="kwd">import</span><span class="pln"> pyinputplus </span><span class="kwd">as</span><span class="pln"> pyip
</span><span class="kwd">import</span><span class="pln"> random</span><span class="pun">,</span><span class="pln"> time

numberOfQuestions </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
correctAnswers </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> questionNumber </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="pln">numberOfQuestions</span><span class="pun">):</span></pre>

<p>
	سنختار داخل حلقة for أرقامًا ذات خانة واحدة لضربها مع بضعها، وسننشِئ المحث prompt الذي سنسأل المستخدم فيه عن قيمة ناتج الضرب <code>‎#Q: N × N =‎</code> الذي تكون فيه Q هي رقم السؤال (من 1 إلى 10) و N هما الرقمان اللذان سنضربهما ببعضهما:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_50" style=""><span class="pln">    </span><span class="com"># اختيار رقمين عشوائيين</span><span class="pln">
    num1 </span><span class="pun">=</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">randint</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pun">)</span><span class="pln">
    num2 </span><span class="pun">=</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">randint</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pun">)</span><span class="pln">

    prompt </span><span class="pun">=</span><span class="pln"> </span><span class="str">'#%s: %s x %s = '</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">questionNumber</span><span class="pun">,</span><span class="pln"> num1</span><span class="pun">,</span><span class="pln"> num2</span><span class="pun">)</span></pre>

<p>
	ستتولى الدالة <code>pyip.inputStr()‎</code> أغلبية خصائص البرنامج، فسنمرر لها المعامل <code>allowRegexes</code> الذي هو قائمة فيها عنصر واحد وهو السلسلة النصية <code>'^%s$'</code>، وسيبدل فيها <code>%s</code> إلى قيمة الجواب الصحيح، وسنستخدم <code>^</code> و <code>$</code> للتحقق أن جواب المستخدم يبدأ وينتهي بالرقم الصحيح، وستحذف المكتبة <code>PyInputPlus</code> أي فراغات بيضاء في بداية ونهاية جواب المستخدم في حال أضاف مسافةً فارغةً خطأً.
</p>

<p>
	القيمة التي سنمررها إلى المعامل <code>blocklistRegexes</code> هي قائمة فيها عنصر هو صف قيمته <code>('.*', 'Incorrect!‎')</code>. أول سلسلة نصية في الصف هي التعبير النمطي الذي يطابق أي شيء، وبالتالي لو أدخل المستخدم أي جواب لا يطابق الجواب الصحيح فسيرفضه البرنامج وستظهر السلسلة النصية <code>'Incorrect!‎'</code> وسنطلب من المستخدم إدخال قيمة مجددًا. لاحظ أيضًا تمرير القيمة 8 إلى المعامل <code>timeout</code> و 3 إلى المعامل <code>limit</code> لكي نحرص أن المستخدم يمتلك 8 ثواني لإدخال إجابة و 3 محاولات فقط لإدخال الرقم الصحيح.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_52" style=""><span class="pln">    </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
        pyip</span><span class="pun">.</span><span class="pln">inputStr</span><span class="pun">(</span><span class="pln">prompt</span><span class="pun">,</span><span class="pln"> allowRegexes</span><span class="pun">=[</span><span class="str">'^%s$'</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">num1 </span><span class="pun">*</span><span class="pln"> num2</span><span class="pun">)],</span><span class="pln">
                              blockRegexes</span><span class="pun">=[(</span><span class="str">'.*'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Incorrect!'</span><span class="pun">)],</span><span class="pln">
                              timeout</span><span class="pun">=</span><span class="lit">8</span><span class="pun">,</span><span class="pln"> limit</span><span class="pun">=</span><span class="lit">3</span><span class="pun">)</span></pre>

<p>
	إذا لم يدخل المستخدم الإجابة خلال مهلة 8 ثواني، فسترمي <code>pyip.inputStr()‎</code> الاستثناء <code>TimeoutException</code>. إذا أدخل المستخدم 3 إجابات خطأ فسيرمى الاستثناء <code>RetryLimitException</code>. لاحظ أنهما جزء من الوحدة <code>PyInputPlus</code> لذا يجب أن نسبقهما بالبادئة <code>pyip.</code>.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_54" style=""><span class="pln">    </span><span class="kwd">except</span><span class="pln"> pyip</span><span class="pun">.</span><span class="typ">TimeoutException</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Out of time!'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">except</span><span class="pln"> pyip</span><span class="pun">.</span><span class="typ">RetryLimitException</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Out of tries!'</span><span class="pun">)</span></pre>

<p>
	هل تذكر أن <a href="https://wiki.hsoub.com/Python/for#.D8.B9.D8.A8.D8.A7.D8.B1.D8.AA.D8.A7_break_.D9.88_else" rel="external">كتلة else</a> تأتي بعد كتل <code><a href="https://wiki.hsoub.com/Python#If" rel="external">if</a></code> أو <code>elif</code>؟ يمكنها أيضًا أن تأتي بعد آخر كتلة <code>except</code>؛ وستنفذ الشيفرة الموجودة في كتلة <code>else </code>في حال عدم رمي أي استثناء في كتلة <code>try</code>، أي في حالتنا حين إدخال المستخدم الإجابة الصحيحة.
</p>

<p>
	استخدام <code>else</code> في هذا السياق هو أمر اختياري، والسبب الرئيسي لاستخدامها بدلًا من كتابة بقية التعابير البرمجية في كتلة <code>try</code> هو تسهيل مقروئية النص.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_56" style=""><span class="pln">    </span><span class="kwd">else</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="str">'Correct!'</span><span class="pun">)</span><span class="pln">
        correctAnswers </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span></pre>

<p>
	ومهما كانت الرسالة التي ستظهر للمستخدم من الرسائل الثلاث "Out of time!‎" أو "Out of tries!‎" أو "Correct!‎" فسيمهل المستخدم لمدة 1 ثانية في نهاية حلقة <code>for</code> ليقرأها.
</p>

<p>
	بعد سؤال المستخدم 10 مرات عبر حلقة <code>for</code> فسنعرض له كم إجابةً صحيحةً قد أجاب:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5916_58" style=""><span class="pln">    time</span><span class="pun">.</span><span class="pln">sleep</span><span class="pun">(</span><span class="lit">1</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="str">'Score: %s / %s'</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">correctAnswers</span><span class="pun">,</span><span class="pln"> numberOfQuestions</span><span class="pun">))</span></pre>

<p>
	الوحدة <code>PyInputPlus</code> مرنة بما يكفي لاستخدامها في مختلف أنواع التطبيقات التي تقبل مدخلات المستخدم من سطر الأوامر كما رأينا في هذا المقال.
</p>

<h2 id="-2">
	الخلاصة
</h2>

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

<p>
	تمتلك الوحدة <code>PyInputPlus</code> دوال مختلفة لأنواع متنوعة من المدخلات، بما في ذلك السلاسل النصية والأرقام والتواريخ، وأسئلة الإيجاب بالموافقة أو الرفض، وأسئلة <code>True</code> أو <code>False</code>، وعناوين البريد الإلكتروني، والملفات.
</p>

<p>
	وفي حين أن الدالة <code>input()‎</code> المضمنة في بايثون تعيد سلسلةً نصيةً دومًا، لكن هذه الدوال تعيد القيمة مع نوع البيانات المناسب لها. تسمح لنا الدالة <code>inputChoice()‎</code> باختصار أحد الخيارات الموجودة مسبقًا، بينما توفر inputMenu()<code>‎</code> قائمة مع خيارات لها أرقام أو أحرف لتسهيل الاختيار.
</p>

<p>
	لكل تلك الدوال ميزات قياسية: فهي تزيل الفراغات من بداية ونهاية المدخلات، وتضبط مهلةً وعددًا لمحاولات الإدخال عبر المعاملين <code>timeout</code> و <code>limit</code>، ونستطيع تمرير قائمة فيها سلاسل نصية تمثل تعابير نمطية إلى المعاملين <code>allowRegexes</code> أو <code>blockRegexes</code> لتضمين أو استبعاد تعابير نمطية محددة من إجابات المستخدم. وعلا ذلك ستوفر عليك وقتك الذي ستقضيه في كتابة حلقات <code>while</code> لإعادة طلب المدخلات من المستخدم.
</p>

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

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

<p>
	بعد أن أصبحت لدينا المعرفة اللازمة في معالجة النصوص والتحقق من مدخلات المستخدم، لنتعلم كيفية القراءة والكتابة من نظام الملفات في حاسوبك.
</p>

<h2 id="-3">
	مشاريع تدريبية
</h2>

<p>
	لكي تتدرب، اكتب برامج لتنفيذ المهام الآتية.
</p>

<h3 id="-4">
	صانع الصندويشات
</h3>

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

<ul>
	<li>
		استخدم <code>inputMenu()‎</code> لنوع الخبز: دقيق كامل wheat، أو خبز أبيض white، أو خبز مختمر sourdough.
	</li>
	<li>
		استخدم <code>inputMenu()‎</code> لنوع البروتين: دجاج chicken، أو ديك turkey، أو بقر beef، أو توفو (جبن نباتي من حليب الصويا) tofu.
	</li>
	<li>
		استخدم <code>inputYesNo()‎</code> لتسأله إذا كان يريد جبنة cheese أم لا.
	</li>
	<li>
		إذا كان يريد جبنة فاستخدم <code>inputMenu()‎</code> لتسأله عن نوعها: شيدر cheddar أو موزاريلا mozzarella أو جبنة سويسرية swiss.
	</li>
	<li>
		استخدم inputYesNo()<code>‎</code> لسؤاله إن كان يريد مايونيز mayo وخردل mustard وخس lettuce وبندورة tomato.
	</li>
	<li>
		استخدم <code>inputInt()‎</code> لتسأله كم صندويشة يريد، احرص أن يكون العدد أكبر من 1.
	</li>
</ul>

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

<h3 id="-5">
	أعد كتابة اختبار جدول الضرب
</h3>

<p>
	لترى كم تسهل عليك الوحدة <code>PyInputPlus</code> عملية التحقق من المدخلات، حاول إعادة إنشاء اختبار جدول الضرب دون استخدامها؛ أي اكتب برنامجًا يسأل المستخدم 10 أسئلة حول جدول الضرب من 0 × 0 حتى 9 × 9. ستحتاج إلى برمجة الميزات الآتية:
</p>

<ul>
	<li>
		إذا أدخل المستخدم الإجابة الصحيحة فسيعرض له البرنامج القيمة "Correct!‎" لثانية ثم ينتقل إلى السؤال الذي يليه.
	</li>
	<li>
		لدى المستخدم ثلاث محاولات قبل أن ينتقل البرنامج إلى السؤال التالي.
	</li>
	<li>
		إذا مرت 8 ثواني بعد عرض السؤال لأول مرة ولم يدخل المستخدم إجابة صحيحةً فسينتقل البرنامج إلى السؤال التالي دون احتساب إجابة السؤال.
	</li>
</ul>

<p>
	قارن بين الشيفرة التي كتبتها وبين الشيفرة في قسم «مشروع: اختبار جدول الضرب».
</p>

<p>
	ترجمة -بتصرف- للفصل <a href="https://automatetheboringstuff.com/2e/chapter8/" rel="external nofollow">Input Validation</a> من كتاب <a href="https://automatetheboringstuff.com/#toc" rel="external nofollow">Automate the Boring Stuff with Python</a>.
</p>

<h2 id="-6">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/python/%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-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2345/https://academy.hsoub.com/programming/python/%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-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2345/" rel="">التعابير النمطية في لغة بايثون python</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/python/%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-lists-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r2339/" rel="">القوائم Lists في لغة بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2322/" rel="">تهيئة بيئة العمل في بايثون Python</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2346</guid><pubDate>Sun, 23 Jun 2024 15:01:01 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x627;&#x628;&#x64A;&#x631; &#x627;&#x644;&#x646;&#x645;&#x637;&#x64A;&#x629; &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646; python</title><link>https://academy.hsoub.com/programming/python/%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-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2345/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_06/------.png.1d1311ccf48c1edc38043a7b55db6d64.png" /></p>
<p>
	من المرجح أنك تعرف كيف تبحث عن النصوص بالضغط على Ctrl+f وإدخال الكلمات التي تريد البحث عنها، في حين أن <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="">التعابير النمطية Regular expressions</a> تنقل الأمور إلى مرحلة أعلى: فهي تسمح لك بتحديد «نمط» النص الذي تبحث عنه، فلو لم تكن تعرف رقم هاتف الشركة في الورقة أمامك، لكنك تعيش في الولايات المتحدة أو كندا، فستعلم أن أرقام الهاتف تتألف من 3 أرقام ثم شرطة <code>-</code>، ثم 4 أرقام أخرى (وقد يبدأ برمز المنطقة وهو 3 أرقام في البداية). أي أنك ستعرف أن ما يلي هو رقم هاتف 415‎-555-1234 لكن 4,155,551,234 ليس رقمًا هاتفيًا.
</p>

<p>
	يمكننا التعرف على مختلف أنماط النصوص بسهولة: فعناوين البريد الإلكتروني تحتوي الرمز @ في منتصفها، و<a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/" rel="">عناوين URL</a> للمواقع تحتوي على نقط وخطوط مائلة، والعناوين الأخبارية تستعمل نسق العنوان Title case، والتاغات في وسائل التواصل الاجتماعي تبدأ برمز <code>#</code> ولا تحتوي على فراغات …إلخ.
</p>

<p>
	التعابير النمطية مفيدة جدًا، لكن قلّة من غير المبرمجين يعرفونها على الرغم من أن أغلبية المحررات النصية الحديثة ومعالجات النصوص مثل <a href="https://academy.hsoub.com/apps/productivity/office/microsoft-word/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%85%D8%A7%D9%8A%D9%83%D8%B1%D9%88%D8%B3%D9%88%D9%81%D8%AA-%D9%88%D9%88%D8%B1%D8%AF-microsoft-word-r835/" rel="">مايكرروسوفت وورد</a> و<a href="https://academy.hsoub.com/apps/productivity/liberoffice/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%AD%D8%B2%D9%85%D8%A9-%D8%A3%D8%AF%D9%88%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%83%D8%AA%D8%A8-%D8%A7%D9%84%D8%AD%D8%B1-libreoffice-r1/" rel="">ليبرأوفيس</a> رايتر يمتلكون خاصيات بحث واستبدال تستعمل التعابير النمطية. والتعابير النمطية تسرع معالجة النصوص لدرجة كبيرة، فلا يستفيد منها مستخدمو برمجيات التحرير فقط، بل المبرمجون أيضًا، ويقول الكاتب الشهير كوري دكتورو أن علينا تدريس التعابير النمطية قبل تدريس البرمجة:
</p>

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

	<p data-gramm="false">
		«معرفة التعابير النمطية تعني الفرق بين حل المشكلة في 3 خطوات وحلها في 3,000 خطوة. إذا كنت تستعملها فستنسى أن المشكلة التي حللتها بضغطات قليلة تأخذ من الناس كمية كبيرة من العمل المضني» – كوري دكتورو بتصرف.
	</p>
</blockquote>

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

<h2 id="">
	مطابقة الأنماط دون استخدام التعابير النمطية
</h2>

<p>
	لنقل أننا نريد البحث عن رقم هاتف يتبع نظام الكتابة الأمريكي في سلسلة نصية، أي يحتوي 3 أرقام ثم شرطة ثم 3 أرقام ثم شرطة ثم 4 أرقام، مثل ‎415-555-4242.
</p>

<p>
	لنكتب دالةً باسم <code>isPhoneNumber()‎</code> للتحقق إن كانت تمثل السلسلة النصية رقم هاتف، وتعيد القيمة <code>True</code> أو <code>False</code>. احفظ الشيفرة الآتية في ملف باسم <code>isPhoneNumber.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_8" style=""><span class="kwd">def</span><span class="pln"> isPhoneNumber</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"> </span><span class="kwd">if</span><span class="pln"> len</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"> </span><span class="lit">12</span><span class="pun">:</span><span class="pln">
         </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">False</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">0</span><span class="pun">,</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="kwd">if</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> text</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">isdecimal</span><span class="pun">():</span><span class="pln">
             </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">
  </span><span class="pun">➌</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> text</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="str">'-'</span><span class="pun">:</span><span class="pln">
         </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">False</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">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</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="kwd">not</span><span class="pln"> text</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">isdecimal</span><span class="pun">():</span><span class="pln">
             </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">
  </span><span class="pun">➎</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> text</span><span class="pun">[</span><span class="lit">7</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="kwd">return</span><span class="pln"> </span><span class="kwd">False</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">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">12</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="kwd">not</span><span class="pln"> text</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">isdecimal</span><span class="pun">():</span><span class="pln">
             </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">
  </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="kwd">print</span><span class="pun">(</span><span class="str">'Is 415-555-4242 a phone number?'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">isPhoneNumber</span><span class="pun">(</span><span class="str">'415-555-4242'</span><span class="pun">))</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Is ABC a phone number?'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">isPhoneNumber</span><span class="pun">(</span><span class="pln">ABC</span><span class="pun">))</span></pre>

<p>
	حين تجربة المثال السابق فسينتج ما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_10" style=""><span class="typ">Is</span><span class="pln"> </span><span class="lit">415</span><span class="pun">-</span><span class="lit">555</span><span class="pun">-</span><span class="lit">4242</span><span class="pln"> a phone number</span><span class="pun">?</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="typ">Is</span><span class="pln"> ABC a phone number</span><span class="pun">?</span><span class="pln">
</span><span class="kwd">False</span></pre>

<p>
	تحتوي الدالة <code>isPhoneNumber()‎</code> على شيفرة تجري عدة عمليات تحقق للتأكد أن السلسلة النصية في المعامل <code>text</code> هي رقم هاتف صالح، وإذا فشلت أي تحقق من هذه التحققات فستعيد الدالة القيمة <code>False</code>.
</p>

<p>
	تبدأ الشيفرة بالتحقق أن السلسلة النصية بطول 12 محرفًا تمامًا ➊، ثم تتحقق أن رقم المنطقة (أي أول 3 محارف في <code>text</code>) تحتوي على محارف رقمية فقط ➋، بقية الدالة تتحقق أن <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> تتبع نمط أرقام الهواتف: يجب أن تكون أول شرطة في الرقم بعد رمز المنطقة ➌، ثم 3 أرقام ➍، ثم شرطة ➎، ثم 4 أرقام ➏، وإن أنهينا كل عمليات التحقق بنجاح فستعيد الدالة <code>True</code> ➐.
</p>

<p>
	استدعاء الدالة isPhoneNumber()<code>‎</code> مع الوسيط '‎415‎-555-4242' سيعيد <code>True</code>، بينما استدعاؤها مع <code>'ABC'</code> سيعيد <code>False</code>، إذ ستفشل أول عملية تحقق لأن السلسلة النصية <code>'ABC'</code> ليست بطول 12 محرفًا.
</p>

<p>
	إذا أردت العثور على رقم هاتف في سلسلة نصية طويل، فستحتاج إلى كتابة المزيد من الشيفرات لمطابقة نمط رقم الهاتف. بدِّل استدعاء الدالة print()<code>‎</code> في المثال السابق إلى ما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_12" style=""><span class="pln">message </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Call me at 415-555-1011 tomorrow. 415-555-9999 is my office.'</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="pln">len</span><span class="pun">(</span><span class="pln">message</span><span class="pun">)):</span><span class="pln">
  </span><span class="pun">➊</span><span class="pln"> chunk </span><span class="pun">=</span><span class="pln"> message</span><span class="pun">[</span><span class="pln">i</span><span class="pun">:</span><span class="pln">i</span><span class="pun">+</span><span class="lit">12</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"> isPhoneNumber</span><span class="pun">(</span><span class="pln">chunk</span><span class="pun">):</span><span class="pln">
          </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Phone number found: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> chunk</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Done'</span><span class="pun">)</span></pre>

<p>
	سينتج البرنامج الناتج الآتي:
</p>

<pre class="ipsCode">Phone number found: 415-555-1011
Phone number found: 415-555-9999
Done
</pre>

<p>
	في كل دورة <a href="https://wiki.hsoub.com/Python/for" rel="external">لحلقة for</a> سنأخذ 12 محرفًا من المتغير <code>message</code> ونسندها إلى المتغير <code>chunk</code> ➊، فمثلًا في أول دورة لحلقة التكرار تكون قيمة i هي 0، وستسند القيمة <code>message[0:12]‎</code> إلى المتغير <code>chunk</code> (أي السلسلة النصية 'Call me at 4')، وفي الدورة التالية تكون قيمة i تساوي 1، وستسند القيمة <code>message[1:13]‎</code> إلى <code>chunk</code> (أي السلسلة النصية 'all me at 41')، بعبارة أخرى: في كل دورة من حلقة <code>for</code> ستتغير قيمة <code>chunk</code> بزيادة مكان بدء عملية الاقتطاع بمقدار واحد، ويكون طولها 12 محرفًا:
</p>

<ul>
	<li>
		'Call me at 4'
	</li>
	<li>
		'all me at 41'
	</li>
	<li>
		'll me at 415'
	</li>
	<li>
		'l me at 415-‎'
	</li>
	<li>
		وهلم جرًا…
	</li>
</ul>

<p>
	سنمرر بعدئذٍ المتغير <code>chunk</code> إلى الدالة isPhoneNumber()<code>‎</code> للتحقق إن كان يطابق نمط أرقام الهواتف ➋، وإذا طابقها فسنطبع القيمة المطابقة.
</p>

<p>
	سنستمر في تنفيذ حلقة التكرار التي ستمر على السلسلة النصية كلها، وستختبر كل 12 محرفًا فيها على حدة، وتطبع قيمة <code>chunk</code> إن أعادت الدالة <code>isPhoneNumber()‎</code> القيمة <code>True</code>، وبعد المرور على جميع محارف السلسلة النصية <code>message</code> فسنطبع الكلمة <code>Done</code>.
</p>

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

<h2 id="-1">
	العثور على تعبير نصي باستخدام التعابير النمطية
</h2>

<p>
	يعمل البرنامج الذي كتبناه في القسم السابق عملًا صحيحًا، لكننا احتجنا إلى كتابة شيفرة كثيرة للقيام بأمر بسيط؛ فطول الدالة <code>isPhoneNumber()‎</code> هو 17 سطرًا لكنها تستطيع مطابقة نمط واحد من أرقام الهواتف. فماذا عن الأرقام المكتوبة بالشكل <code>415.555.4242</code> أو <code>‎(415) 555-4242</code>؟ ماذا لو كان هنالك رمز تحويل بعد رقم الهاتف مثل ‎415-555-4242 x99؟ ستفشل الدالة <code>isPhoneNumber()‎</code> بمطابقتها. صحيحٌ أنك تستطيع كتابة شيفرات إضافية للتحقق من هذه الحالات، لكن هنالك طريقة أسهل بكثير.
</p>

<p>
	التعابير النمطية Regular Expression أو اختصارًا Regex تصف نمط النصوص (ومن هنا أتى اسمها). فمثلًا <code>‎\d</code> في صياغة التعابير النمطية تعني محرف رقمي، أي رقم مفرد من 0 حتى 9. ويستعمل التعبير النمطي <code>‎\d\d\d-\d\d\d-\d\d\d\d</code> في بايثون لمطابقة النص الذي تطابقه الدالة <code>isPhoneNumber()‎</code> السابقة: سلسلة من 3 أرقام، ثم شرطة، ثم 3 أرقام، ثم شرطة، ثم 4 أرقام. ولن تطابق أي سلسلة نصية لها نمط آخر التعبير النمطي <code>‎\d\d\d-\d\d\d-\d\d\d\d</code>.
</p>

<p>
	لكن يمكن أن تكون التعابير النمطية أعقد من ذلك بكثير، فمثلًا إضافة الرقم 3 بين قوسين مجعدين {3} يعني «طابق هذا النمط 3 مرات»، وبالتالي يمكننا كتابة التعبير النمطي السابق بشكل مختصر <code>‎\d{3}-\d{3}-\d{4}‎</code> وستكون النتيجة نفسها.
</p>

<h3 id="regex">
	إنشاء كائنات Regex
</h3>

<p>
	جميع دوال التعابير النمطية موجودة في الوحدة <code>re</code>، وعلينا استيرادها أولًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_15" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> re</span></pre>

<p>
	ملاحظة: أغلبية الأمثلة في هذا المقال تستعمل الوحدة re، لذا من المهم أن تتذكر استيرادها في بداية كل سكربت أو حينما تعيد تشغيل محرر Mu، وإلا فستحصل على رسالة الخطأ NameError: name 're' is not defined.
</p>

<p>
	تمرير سلسلة نصية تمثل التعبير النمطي إلى <code>re.compile()‎</code> سيعيد كائن <code>Regex</code>.
</p>

<p>
	لإنشاء كائن <code>Regex</code> يطابق نمط أرقام الهواتف السابق، فأدخل ما يلي إلى الطرفية التفاعلية. تذكر أن <code>‎\d</code> تعني «محرف رقمي»، و <code>‎</code>\d\d\d-\d\d\d-\d\d\d\d هو التعبير النمطي الذي سيطابق رقم الهاتف.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_17" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> phoneNumRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'\d\d\d-\d\d\d-\d\d\d\d'</span><span class="pun">)</span></pre>

<p>
	يحتوي المتغير <code>phoneNumRegex</code> الآن على كائن <code>Regex</code>.
</p>

<h3 id="regex-1">
	مطابقة كائنات Regex
</h3>

<p>
	يمتلك الكائن <code>Regex</code> التابع search()<code>‎</code> الذي يبحث في السلسلة النصية التي مررت إليها لأي مطابقة للتعبير النمطية. سيعيد التابع search()<code>‎</code> القيمة <code>None</code> إذا لم يُطابَق التعبير النمطي في السلسلة النصية، وإذا عُثر على التعبير النمطي فسيعيد التابع <code>search()‎</code> كائن <code>Match</code>، الذي فيه التابع <code>group()‎</code> الذي يعيد النص الذي جرت مطابقته مع التعبير النمطي (سنشرح المجموعات لاحقًا فلا تقلق):
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_19" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> phoneNumRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'\d\d\d-\d\d\d-\d\d\d\d'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo </span><span class="pun">=</span><span class="pln"> phoneNumRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'My number is 415-555-4242.'</span><span class="pun">)</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="str">'Phone number found: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">group</span><span class="pun">())</span><span class="pln">
</span><span class="typ">Phone</span><span class="pln"> number found</span><span class="pun">:</span><span class="pln"> </span><span class="lit">415</span><span class="pun">-</span><span class="lit">555</span><span class="pun">-</span><span class="lit">4242</span></pre>

<p>
	اسم المتغير mo هو اسم عام لكائنات <code>Match</code>، قد يبدو المثال السابق معقدًا لكنه أقصر بكثير من برنامج <code>isPhoneNumber.py</code>.
</p>

<p>
	بدايةً مررنا التعبير النمطي الذي نريده إلى <code>re.compile()‎</code> وحفظنا كائن <code>Regex</code> الناتج في المتغير <code>phoneNumRegex</code>، ثم استدعينا التابع <code>search()‎</code> على <code>phoneNumRegex</code> ومررنا السلسلة النصية التي نريد البحث فيها عن النمط إلى التابع <code>search()‎</code>.
</p>

<p>
	ستخزن نتيجة البحث في المتغير <code>mo</code>، ونحن نعرف في هذا المثال أن التابع سيعيد الكائن <code>Match</code>، ولمعرفتنا أن المتغير <code>mo</code> سيحتوي على كائن <code>Match</code> وليس قيمة فارغة <code>None</code>، فاستدعينا التابع group()<code>‎</code> على <code>mo</code> لإعادة الناتج، ولأننا كتبنا mo.group()<code>‎</code> داخل الدالة <code>print()‎</code> فسنعرض الناتج الذي جربت مطابقته <code>415‎-555-4242</code>.
</p>

<h3 id="-2">
	مراجعة لعملية لمطابقة التعابير النمطية
</h3>

<p>
	هنالك عدة خطوات لاستعمال التعابير النمطية في <a href="https://academy.hsoub.com/python/" rel="">بايثون</a>، وكل واحدة منها بسيطة وسهلة:
</p>

<ol>
	<li>
		استيراد الوحدة <code>Regex</code> بكتابة <code>import re</code>.
	</li>
	<li>
		إنشاء كائن <code>Regex</code> مع الدالة <code>re.compile()‎</code>، وتذكر أن تستعمل سلسلة نصية خام <code>raw</code> بكتابة r قبلها.
	</li>
	<li>
		تمرير السلسلة النصية التي تريد البحث فيها إلى التابع <code>search()‎</code> الذي سيعيد كائن من النوع <code>Match</code>.
	</li>
	<li>
		استدعاء الدالة <code>group()‎</code> للكائن <code>Match</code> التي تعيد السلسلة النصية المطابقة.
	</li>
</ol>

<p>
	ملاحظة: صحيحٌ أنني أنصحك أن تجرب الشيفرات في الطرفية التفاعلية لكنك تستطيع استخدام تطبيقات ويب لاختبار التعابير النمطية التي تظهر لك بوضوح كيف يطابق التعبير النمطي النص الذي أدخلته. أنصحك بتجربة <a href="https://pythex.org" rel="external nofollow">موقع pythex</a>.
</p>

<h2 id="-3">
	ميزات إضافية لمطابقة النصوص عبر التعابير النمطية
</h2>

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

<h3 id="-4">
	التجميع مع الأقواس
</h3>

<p>
	لنقل أنك تريد أن تفصل رقم المنطقة من بقية رقم الهاتف. إذا أضفنا أقواسًا في التعابير النمطية فستنشِئ مجموعات groups كما في <code>(‎\d\d\d)-(\d\d\d-\d\d\d\d)</code>، ثم يمكننا استخدام التابع <code>group()‎</code> للكائن <code>Match</code> للحصول على النص المطابق من مجموعة معينة.
</p>

<p>
	ستخزن القيمة المطابقة من أول مجموعة في المجموعة 1، والمجموعة الثانية في 2… وإذا مررنا القيمة 1 أو 2 إلى التابع group()<code>‎</code> فسنحصل على أجزاء مختلفة من النص الذي جرت مطابقته. أما تمرير القيمة 0 أو عدم تمرير أي قيمة إلى التابع <code>group()‎</code> فسيعيد كامل النص الذي جرت مطابقته من التعبير النمطي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_23" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> phoneNumRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'(\d\d\d)-(\d\d\d-\d\d\d\d)'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo </span><span class="pun">=</span><span class="pln"> phoneNumRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'My number is 415-555-4242.'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">group</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
</span><span class="str">'415'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">group</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
</span><span class="str">'555-4242'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">group</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
</span><span class="str">'415-555-4242'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'415-555-4242'</span></pre>

<p>
	إذا أردت الحصول على جميع المجموعات في آن واحد، فاستعمل التابع <code>groups()‎</code> (لاحظ أن اسم التابع بالجمع وليس المفرد):
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_25" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">groups</span><span class="pun">()</span><span class="pln">
</span><span class="pun">(</span><span class="str">'415'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'555-4242'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> areaCode</span><span class="pun">,</span><span class="pln"> mainNumber </span><span class="pun">=</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">groups</span><span class="pun">()</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">areaCode</span><span class="pun">)</span><span class="pln">
</span><span class="lit">415</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">mainNumber</span><span class="pun">)</span><span class="pln">
</span><span class="lit">555</span><span class="pun">-</span><span class="lit">4242</span></pre>

<p>
	يعيد التابع <code>mo.groups()‎</code> صفًا tuple فيه أكثر من قيمة، ويمكنك استعمال الإسناد المتعدد لإسناد كل قيمة إلى متغير كما في السطر الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_27" style=""><span class="pln">areaCode</span><span class="pun">,</span><span class="pln"> mainNumber </span><span class="pun">=</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">groups</span><span class="pun">()‎</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_29" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> phoneNumRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'(\(\d\d\d\)) (\d\d\d-\d\d\d\d)'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo </span><span class="pun">=</span><span class="pln"> phoneNumRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'My phone number is (415) 555-4242.'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">group</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
</span><span class="str">'(415)'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">group</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
</span><span class="str">'555-4242'</span></pre>

<p>
	سيطابق المحرفان المهربان ‎`)‎<code>و ‎</code>`(‎ في السلسلة النصية الخام الممررة إلى الدالة <code>re.compile()‎</code> الأقواس في السلسلة النصية التي سنبحث فيها. هنالك معانٍ خاصة للمحارف الآتية في التعابير النمطية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_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">  </span><span class="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>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_33" style=""><span class="pln">\.  \^  \$  \*  \+  \?  \{  \}  \[  \]  \\  \|  \(  \)</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_35" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'(\(Parentheses\)'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
    </span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">
re</span><span class="pun">.</span><span class="pln">error</span><span class="pun">:</span><span class="pln"> missing </span><span class="pun">),</span><span class="pln"> unterminated subpattern at position </span><span class="lit">0</span></pre>

<p>
	تقول لك رسالة الخطأ أن هنالك قوس مفتوح في الفهرس 0 من السلسلة النصية r'((Parentheses)'<code>‎</code> الذي لا يوجد له قوس إغلاق.
</p>

<h3 id="-5">
	مطابقة أكثر من مجموعة باستخدام الخط العمودي
</h3>

<p>
	محرف الخط العمودي | الذي يسمى أيضًا بالأنبوب Pipe يستعمل في أي مكان تريد فيه مطابقة أحد التعابير الموفرة، أي لنقل أن لدينا التعبير النمطي <code>r'Batman|Yasmin'‎</code> الذي سيطابق <code>'Batman'</code> أو <code>'Yasmin'</code>.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_37" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> heroRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile </span><span class="pun">(</span><span class="pln">r</span><span class="str">'Batman|Yasmin'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo1 </span><span class="pun">=</span><span class="pln"> heroRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'Batman and Yasmin'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo1</span><span class="pun">.</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'Batman'</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo2 </span><span class="pun">=</span><span class="pln"> heroRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'Yasmin and Batman'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo2</span><span class="pun">.</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'Yasmin'</span></pre>

<p>
	ملاحظة: يمكنك العثور على جميع حالات المطابقة باستخدام التابع <code>findall()‎</code> المشروحة في هذا المقال.
</p>

<p>
	يمكنك أيضًا استخدام الخط العمودي لمطابقة تعابير فرعية مختلفة، فمثلًا لو قلنا أننا نريد مطابقة أي سلسلة نصية من <code>'Batman'</code> و <code>'Batmobile'</code> و <code>'Batcopter'</code> و <code>'Batbat'</code>، ولأن كل هذه السلاسل النصية تبدأ بالكلمة Bat فمن المنطقي أن نكتب هذه السابقة مرة واحدة، ويمكننا فعل ذلك عبر الأقواس كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_39" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> batRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'Bat(man|mobile|copter|bat)'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo </span><span class="pun">=</span><span class="pln"> batRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'Batmobile lost a wheel'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'Batmobile'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">group</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
</span><span class="str">'Mobile'</span></pre>

<p>
	استدعاء التابع <code>mo.group()‎</code> يعيد النص <code>'Batmobile'</code> بينما mo.group(1)<code>‎</code> يعيد النص المطابق داخل مجموعة الأقواس الأولى، أي <code>'mobile'</code>. استخدام الخط العمودي <code>|</code> يتيح لنا مطابقة أحد التعابير النمطية الموفرة، وإذا أردنا أن نطابق الخط العمودي نفسه في السلسلة النصية المبحوث فيها فلا ننسى تهريبه <code>‎|‎</code>.
</p>

<h3 id="-6">
	المطابقة الاختيارية عبر إشارة الاستفهام
</h3>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_41" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> batRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'Bat(wo)?man'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo1 </span><span class="pun">=</span><span class="pln"> batRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'The Adventures of Batman'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo1</span><span class="pun">.</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'Batman'</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo2 </span><span class="pun">=</span><span class="pln"> batRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'The Adventures of Batwoman'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo2</span><span class="pun">.</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'Batwoman'</span></pre>

<p>
	لاحظ أن الجزء ‎<code>(wo)?</code>‎ يعني أن النمط <code>wo</code> هو مجموعة اختيارية، فسيطابَق التعبير النمطي لو احتوت السلسلة النصية على 0 أو 1 من السلسلة النصية <code>wo</code> داخلها. وهذا يعني أن التعبير النمطي سيطابق <code>'Batwoman'</code> و <code>'Batman'</code> معًا.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_43" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> phoneRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'(\d\d\d-)?\d\d\d-\d\d\d\d'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo1 </span><span class="pun">=</span><span class="pln"> phoneRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'My number is 415-555-4242'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo1</span><span class="pun">.</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'415-555-4242'</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo2 </span><span class="pun">=</span><span class="pln"> phoneRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'My number is 555-4242'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo2</span><span class="pun">.</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'555-4242'</span></pre>

<p>
	يمكنك أن تقول أن <code>?</code> يعني «طابق النمط الفرعي السابق 0 مرة أو مرة واحدة»، وإذا أردنا مطابقة علامة الاستفهام فلا ننسى تهريبها بكتابة ‎\?<code>‎</code>.
</p>

<h3 id="-7">
	المطابقة صفر مرة أو أكثر باستخدام رمز النجمة
</h3>

<p>
	رمز النجمة <code>*</code> asterisk يعني «طابق صفر مرة أو أكثر»، فاستعمال النجمة يعني أن التعبير النمطي الذي يسبقها سيطابق لأي عدد من المرات في السلسلة النصية؛ فقد لا يكون موجودًا أو يكون مكررًا مرات كثيرة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_45" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> batRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'Bat(wo)*man'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo1 </span><span class="pun">=</span><span class="pln"> batRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'The Adventures of Batman'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo1</span><span class="pun">.</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'Batman'</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo2 </span><span class="pun">=</span><span class="pln"> batRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'The Adventures of Batwoman'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo2</span><span class="pun">.</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'Batwoman'</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo3 </span><span class="pun">=</span><span class="pln"> batRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'The Adventures of Batwowowowoman'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo3</span><span class="pun">.</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'Batwowowowoman'</span></pre>

<p>
	لاحظ أن التعبير النمطي <code>‎(wo)*‎</code> سيُطابَق 0 مرة في <code>'Batman'</code>، ومرة واحدة في <code>'Batwoman'</code>، وأربع مرات في <code>'Batwowowowoman'</code>. إذا أردنا مطابقة النجمة نفسها فلا ننسَ تهريبها بكتابة <code>‎\*‎</code>.
</p>

<h3 id="-8">
	المطابقة مرة واحدة أو أكثر باستخدام إشارة الجمع
</h3>

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

<p>
	قارن بين أثر رمز النجمة في القسم السابق والمثال الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_47" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> batRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'Bat(wo)+man'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo1 </span><span class="pun">=</span><span class="pln"> batRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'The Adventures of Batwoman'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo1</span><span class="pun">.</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'Batwoman'</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo2 </span><span class="pun">=</span><span class="pln"> batRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'The Adventures of Batwowowowoman'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo2</span><span class="pun">.</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'Batwowowowoman'</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo3 </span><span class="pun">=</span><span class="pln"> batRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'The Adventures of Batman'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo3 </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">None</span><span class="pln">
</span><span class="kwd">True</span></pre>

<p>
	التعبير النمطي <code>Bat(wo)+man</code> لا يطابق السلسلة النصية <code>'The Adventures of Batman'</code> لأن من المطلوب وجود التعبير الفرعي <code>wo</code> مرة واحدة على الأقل. إذا أردنا مطابقة إشارة الزائد فلا ننسى تهريبها ‎+<code>‎</code>.
</p>

<h3 id="-9">
	مطابقة النمط لعدد معين من المرات باستخدام الأقواس المجعدة
</h3>

<p>
	إذا كانت لديك مجموعة تريد تكرارها لعدد معين من المرات، فأتبع تلك السلسلة برقم محاط بأقواس <code>{}</code>. فمثلًا التعبير النمطي <code>‎(Ha){3}‎</code> يطابق السلسلة النصية <code>'HaHaHa'</code> لكنه لن يطابق <code>'HaHa'</code> لأنها تحتوي على تكرارين للتعبير <code>Ha</code> فقط.
</p>

<p>
	وبدلًا من كتابة رقم واحد، يمكننا تحديد مجال من التكرارات بكتابة الحد الأدنى، ثم فاصلة، ثم الحد الأقصى ضمن القوسين، مثلًا التعبير النمطي ‎<code>(Ha){3,5}</code>‎ سيطابق <code>'HaHaHa'</code> و <code>'HaHaHaHa'</code> و <code>'HaHaHaHaHa'</code>.
</p>

<p>
	يمكنك ألّا تحدد الرقم الأدنى أو الأقصى ضمن القوسين لتترك المجال مفتوحًا، فمثلًا ‎(Ha){3,}<code>‎</code> سيطبق 3 تكرارات أو أكثر من المجموعة (Ha)، بينما ‎<code>(Ha){,5}</code>‎ سيطابق المجموعة (Ha) من 0 حتى 5 تكرارات.
</p>

<p>
	ستساعدنا الأقواس المجعدة على تقصير التعبير النمطي، إذ يتساوى التعبيران النمطيان الآتيان:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_49" style=""><span class="pun">(</span><span class="typ">Ha</span><span class="pun">){</span><span class="lit">3</span><span class="pun">}</span><span class="pln">
</span><span class="pun">(</span><span class="typ">Ha</span><span class="pun">)(</span><span class="typ">Ha</span><span class="pun">)(</span><span class="typ">Ha</span><span class="pun">)</span></pre>

<p>
	وسيتساوي أيضًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_51" style=""><span class="pun">(</span><span class="typ">Ha</span><span class="pun">){</span><span class="lit">3</span><span class="pun">,</span><span class="lit">5</span><span class="pun">}</span><span class="pln">
</span><span class="pun">((</span><span class="typ">Ha</span><span class="pun">)(</span><span class="typ">Ha</span><span class="pun">)(</span><span class="typ">Ha</span><span class="pun">))|((</span><span class="typ">Ha</span><span class="pun">)(</span><span class="typ">Ha</span><span class="pun">)(</span><span class="typ">Ha</span><span class="pun">)(</span><span class="typ">Ha</span><span class="pun">))|((</span><span class="typ">Ha</span><span class="pun">)(</span><span class="typ">Ha</span><span class="pun">)(</span><span class="typ">Ha</span><span class="pun">)(</span><span class="typ">Ha</span><span class="pun">)(</span><span class="typ">Ha</span><span class="pun">))</span></pre>

<p>
	جرب ما يلي في الطرفية التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_53" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> haRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'(Ha){3}'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo1 </span><span class="pun">=</span><span class="pln"> haRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'HaHaHa'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo1</span><span class="pun">.</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'HaHaHa'</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo2 </span><span class="pun">=</span><span class="pln"> haRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'Ha'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo2 </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">None</span><span class="pln">
</span><span class="kwd">True</span></pre>

<p>
	سيطابق ‎(Ha){3}<code>‎</code> السلسلة النصية <code>'HaHaHa'</code> لكنه لن يطابق <code>'Ha'</code>، وبالتالي سيعيد التابع <code>search()‎</code> القيمة <code>None</code>.
</p>

<h2 id="-10">
	المطابقة الجشعة والمطابقة غير الجشعة
</h2>

<p>
	لمّا كان التعبير ‎<code>(Ha){3,5}</code>‎ يطابق 3 أو 4 أو 5 تكرارات من Ha في السلسلة النصية <code>'HaHaHaHaHa'</code> فستتسائل لماذا يعيد استدعاء التابع <code>group()‎</code> على الكائن <code>Match</code> السلسلة النصية <code>'HaHaHaHaHa'</code> بدلًا من الاحتمالات الأخرى، ففي النهاية <code>'HaHaHa'</code> و <code>'HaHaHaHa'</code> هي مطابقات صالحة في التعبير النمطي <code>‎</code>(Ha){3,5}‎.
</p>

<p>
	تكون التعابير النمطية في بايثون جشعة greedy افتراضيًا، وهذا يعني أنه في الحالات غير المحددة ستحاول التعابير النمطية مطابقة أطول سلسلة نصية ممكنة؛ أما المطابقة غير الجشعة non-greedy (وتسمى أحيانًا بالمطابقة الكسولة lazy) تطابق أقصر سلسلة نصية ممكنة، ونستطيع تحديد أننا نريد مطابقة غير جشعة عبر وضع علامة استفهام بعد قوس الإغلاق المجعد.
</p>

<p>
	جرب ما يلي ولاحظ الاختلافات بين النسخة الجشعة وغير الجشعة وماذا ستطابق في السلسلة النصية نفسها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_55" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> greedyHaRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'(Ha){3,5}'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo1 </span><span class="pun">=</span><span class="pln"> greedyHaRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'HaHaHaHaHa'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo1</span><span class="pun">.</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'HaHaHaHaHa'</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> nongreedyHaRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'(Ha){3,5}?'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo2 </span><span class="pun">=</span><span class="pln"> nongreedyHaRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'HaHaHaHaHa'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo2</span><span class="pun">.</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'HaHaHa'</span></pre>

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

<h2 id="findall">
	التابع findall()‎
</h2>

<p>
	بالإضافة إلى التابع search()<code>‎</code> تمتلك كائنات <code>Regex</code> التابع findall()<code>‎</code>، وفي حين أن التابع <code>search()‎</code> يعيد كائن <code>Match</code> لأول جزء مطابَق من السلسلة النصي التي نبحث فيها، يعيد التابع findall()<code>‎</code> جميع المطابقات في السلسلة النصية.
</p>

<p>
	لنرى كيف يعيد التابع <code>search()‎</code> الكائن <code>Match</code> على أول سلسلة نصية مطابقة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_57" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> phoneNumRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'\d\d\d-\d\d\d-\d\d\d\d'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo </span><span class="pun">=</span><span class="pln"> phoneNumRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'Cell: 415-555-9999 Work: 212-555-0000'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'415-555-9999'</span></pre>

<p>
	وفي المقابل لن يعيد التابع <code>findall()‎</code> الكائن <code>Match</code>، بل قائمة فيها سلاسل نصية، لطالما لم تكن هنالك مجموعات فرعية في التعبير النمطي؛ وتمثل كل سلسلة نصية في القائمة المعادة الجزء من النص المطابق للتعبير النمطي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_59" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> phoneNumRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'\d\d\d-\d\d\d-\d\d\d\d'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># لا توجد تعابير فرعية</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> phoneNumRegex</span><span class="pun">.</span><span class="pln">findall</span><span class="pun">(</span><span class="str">'Cell: 415-555-9999 Work: 212-555-0000'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="str">'415-555-9999'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'212-555-0000'</span><span class="pun">]</span></pre>

<p>
	أما لو كانت هنالك مجموعات أو تعابير فرعية في التعبير النمطي، فسيعيد التابع <code>findall()‎</code> قائمةً من الصفوف tuples، ويمثل كل صف مطابقةً، وعناصر الصف هي السلاسل النصية المطابقة لكل تعبير فرعي في التعبير النمطي.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_61" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> phoneNumRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'(\d\d\d)-(\d\d\d)-(\d\d\d\d)'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># توجد تعابير فرعية</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> phoneNumRegex</span><span class="pun">.</span><span class="pln">findall</span><span class="pun">(</span><span class="str">'Cell: 415-555-9999 Work: 212-555-0000'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[(</span><span class="str">'415'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'555'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'9999'</span><span class="pun">),</span><span class="pln"> </span><span class="pun">(</span><span class="str">'212'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'555'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'0000'</span><span class="pun">)]</span></pre>

<p>
	لنلخص ما الذي يعيد التابع <code>findall()‎</code>:
</p>

<p>
	عند استدعائه على تعبير نمطي لا يحتوي على مجموعات، مثل <code>‎\d\d\d-\d\d\d-\d\d\d\d</code> فسيعيد التابع findall()<code>‎</code> قائمةً من السلاسل النصية مثل ‎['415-555-9999', '212-555-0000']<code>‎</code>. عند استدعائه على تعبير نمطي يحتوي على مجموعات أو تعابير نمطية فرعية، مثل <code>(‎\d\d\d)-(\d\d\d)-(\d\d\d\d)</code> فسيعيد التابع <code>findall()‎</code> قائمةً من الصفوف التي تحتوي على سلاسل نصية، سلسلة نصية لكل مجموعة، مثل:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_63" style=""><span class="pun">‎[(</span><span class="str">'415'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'555'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'9999'</span><span class="pun">),</span><span class="pln"> </span><span class="pun">(</span><span class="str">'212'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'555'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'0000'</span><span class="pun">)]‎</span></pre>

<h2 id="-11">
	فئات المحارف
</h2>

<p>
	تعلمنا في مثال أرقام الهواتف السابق أن <code>‎</code>\d يطابق أي رقم، أي أنه اختصار للتعبير ‎<code>(0|1|2|3|4|5|6|7|8|9)</code>‎. هنالك عدد من فئات المحارف المختصرة، والتي تستطيع معرفتها من الجدول 7-1.
</p>

<table>
	<thead>
		<tr>
			<th>
				اختصار فئة المحارف
			</th>
			<th>
				يمثل
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				<code>\d</code>
			</td>
			<td>
				أي محرف يمثل رقمًا من 0 حتى 9
			</td>
		</tr>
		<tr>
			<td>
				<code>\D</code>
			</td>
			<td>
				أي محرف ليس رقمًا من 0 حتى 9
			</td>
		</tr>
		<tr>
			<td>
				<code>\w</code>
			</td>
			<td>
				أي حرف أو رقم أو الشرطة السفلية، يمكننا أن نقول أنه يطابق محارف «الكلمات»
			</td>
		</tr>
		<tr>
			<td>
				<code>\W</code>
			</td>
			<td>
				أي محرف ليس حرفًا أو رقمًا أو شرطةً سفلية (عكس ‎\w)
			</td>
		</tr>
		<tr>
			<td>
				<code>\s</code>
			</td>
			<td>
				أي مسافة فارغة أو مسافة جدولة أو سطر جديد، يمكننا أن نقول أنه يطابق «الفراغات»
			</td>
		</tr>
		<tr>
			<td>
				<code>\S</code>
			</td>
			<td>
				أي محرف ليس فراغًا أو مسافة جدولة أو سطر جديد
			</td>
		</tr>
	</tbody>
</table>

<p style="text-align: center;">
	الجدول 7-1: اختصارات فئات المحارف الشائعة
</p>

<p>
	تساعد فئات المحارف Character classes على اختصار التعابير النمطية، ففئة المحارف [0‎-5] تطابق الأرقام من 0 إلى 5 فقط، وهذا أكثر اختصارًا من كتابة (0‎|1|2|3|4|5)، لاحظ أننا نملك <code>\d</code> لمطابقة الأرقام فقط، لكن ‎\w يطابق الأرقام والأحرف والشرطة السفلية <code>_</code>، ولا يوجد اختصار لمطابقة الأحرف فقط، لكنك تستطيع أن تكتب <code>[a-zA-Z]</code> التي سنشرحها لاحقًا.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_65" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> xmasRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'\d+\s\w+'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> xmasRegex</span><span class="pun">.</span><span class="pln">findall</span><span class="pun">(</span><span class="str">'12 drummers, 11 pipers, 10 lords, 9 ladies, 8 maids, 7
swans, 6 geese, 5 rings, 4 birds, 3 hens, 2 doves, 1 partridge'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="str">'12 drummers'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'11 pipers'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'10 lords'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'9 ladies'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'8 maids'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'7 swans'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'6
geese'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'5 rings'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'4 birds'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'3 hens'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'2 doves'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'1 partridge'</span><span class="pun">]</span></pre>

<p>
	سيطابق التعبير النمطي ‎\d+\s\w+<code>‎</code> أي نص فيه رقم واحد أو أكثر <code>‎\d+‎</code> يكون متبوعًا بفراغ <code>‎\s</code> ويكون متبوعًا برقم أو حرف أو شرطة سفلية<br>
	<code>‎\w+‎</code>. سيعيد التابع <code>findall()‎</code> السلاسل النصية المطابقة من التعبير النمطي في قائمة.
</p>

<h2 id="-12">
	كتابة فئات محارف مخصصة
</h2>

<p>
	هنالك حالات نحتاج فيها إلى استخدام مجموعة من المحارف لكن الفئات المختصرة الشائعة (مثل <code>‎\d</code> و <code>‎\w</code> و <code>‎\s</code> …إلخ.) غير مناسبة لحالتنا؛ لذا يمكننا تعريف فئات المحارف بأنفسنا باستعمال الأقواس المربعة <code>[]</code>. فمثلًا فئة المحارف <code>[aeiouAEIOU]</code> ستطابق أي حرف صوتي سواءً كان بالحالة الصغيرة أو الكبيرة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_67" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> vowelRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'[aeiouAEIOU]'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> vowelRegex</span><span class="pun">.</span><span class="pln">findall</span><span class="pun">(</span><span class="str">'RoboCop eats baby food. BABY FOOD.'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="str">'o'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'o'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'o'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'e'</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">'a'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'o'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'o'</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">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">]</span></pre>

<p>
	يمكنك أيضًا تضمين مجال من الأرقام أو الأحرف باستخدام الشرطة، فمثلًا فئة المحارف <code>[a-zA-Z0-9]</code> ستطابق جميع الأحرف الصغيرة والأحرف الكبيرة والأرقام.
</p>

<p>
	لاحظ أن رموز التعابير النمطية العادية لن تفسر داخل الأقواس المربعة، فلا حاجة إلى تهريب المحارف . أو <code>*</code> أو <code>?</code> أو <code>()</code> بخط مائل خلفي. فمثلًا فئة المحارف <code>[‎0-5.‎]</code> تطابق الأعداد من 0 إلى 5 ونقطة. ولا حاجة إلى تهريبها وكتابة <code>[0‎-5\.‎]</code>.
</p>

<p>
	إذا وضعنا رمز القبعة caret <code>^</code> بعد قوس بداية فئة المحارف فسيعني «الرفض»، أي سيعكس محتويات فئة المحارف، أي أنها ستطابق أي محرف ليس موجودًا في فئة المحارف المحددة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_69" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> consonantRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'[^aeiouAEIOU]'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> consonantRegex</span><span class="pun">.</span><span class="pln">findall</span><span class="pun">(</span><span class="str">'RoboCop eats baby food. BABY FOOD.'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="str">'R'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'b'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'C'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'p'</span><span class="pun">,</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'t'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'s'</span><span class="pun">,</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'b'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'b'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'y'</span><span class="pun">,</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'f'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'d'</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">'B'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'B'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Y'</span><span class="pun">,</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'F'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'D'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'.'</span><span class="pun">]</span></pre>

<p>
	فبدلًا من مطابقة الأحرف الصوتية، أصبحت فئة المحارف تطابق كل شيء عدا الأحرف الصوتية.
</p>

<h2 id="-13">
	رمز القبعة ورمز الدولار
</h2>

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

<p>
	يمكننا أن نستعمل الرمزين <code>^</code> و <code>$</code> معًا للإشارة إلى أن السلسلة النصية كلها يجب أن تطابق التعبير النمطي، أي لا يسمح بإجراء مطابقة جزئية على السلسلة النصية فقط.
</p>

<p>
	لنأخذ مثالًا بسيطًا التعبير النمطي r'^Hello'<code>‎</code> الذي سيطابق أي سلسلة نصية تبدأ بالكلمة <code>'Hello'</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_71" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> beginsWithHello </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'^Hello'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> beginsWithHello</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'Hello, world!'</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">Match</span><span class="pln"> object</span><span class="pun">;</span><span class="pln"> span</span><span class="pun">=(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">),</span><span class="pln"> match</span><span class="pun">=</span><span class="str">'Hello'</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> beginsWithHello</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'He said hello.'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">None</span><span class="pln">
</span><span class="kwd">True</span></pre>

<p>
	التعبير النمطي <code>‎r'\d$'‎</code> يطابق السلاسل النصية التي تنتهي برقم من 0 إلى 9:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_73" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> endsWithNumber </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'\d$'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> endsWithNumber</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'Your number is 42'</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">Match</span><span class="pln"> object</span><span class="pun">;</span><span class="pln"> span</span><span class="pun">=(</span><span class="lit">16</span><span class="pun">,</span><span class="pln"> </span><span class="lit">17</span><span class="pun">),</span><span class="pln"> match</span><span class="pun">=</span><span class="str">'2'</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> endsWithNumber</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'Your number is forty two.'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">None</span><span class="pln">
</span><span class="kwd">True</span></pre>

<p>
	أما التعبير ‎r'^\d+$'<code>‎</code> فهو يطابق السلاسل النصية التي تحتوي على رقم واحد على الأقل:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_75" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wholeStringIsNum </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'^\d+$'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wholeStringIsNum</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'1234567890'</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">Match</span><span class="pln"> object</span><span class="pun">;</span><span class="pln"> span</span><span class="pun">=(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">),</span><span class="pln"> match</span><span class="pun">=</span><span class="str">'1234567890'</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wholeStringIsNum</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'12345xyz67890'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">None</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> wholeStringIsNum</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'12  34567890'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">None</span><span class="pln">
</span><span class="kwd">True</span></pre>

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

<h2 id="-14">
	حرف البدل
</h2>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_77" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> atRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'.at'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> atRegex</span><span class="pun">.</span><span class="pln">findall</span><span class="pun">(</span><span class="str">'The cat in the hat sat on the flat mat.'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'hat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'sat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'lat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'mat'</span><span class="pun">]</span></pre>

<p>
	تذكر أن النقطة ستطابق محرفًا واحدًا فقط، وهذا هو السبب في أن التعبير النمطي طابق lat في السلسلة النصية flat فقط. إذا أردنا البحث عن رمز النقطة فلا ننسى تهريبه عبر خط مائل خلفي <code>‎\.‎</code>.
</p>

<h3 id="-15">
	مطابقة كل شيء مع النقطة والنجمة
</h3>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_79" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> nameRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'First Name: (.*) Last Name: (.*)'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo </span><span class="pun">=</span><span class="pln"> nameRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'First Name: Al Last Name: Sweigart'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">group</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
</span><span class="str">'Al'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">group</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
</span><span class="str">'Sweigart'</span></pre>

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

<p>
	جرب المثال الآتي لترى الفرق بين النسخة الجشعة وغير الجشعة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_81" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> nongreedyRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'&lt;.*?&gt;'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo </span><span class="pun">=</span><span class="pln"> nongreedyRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'&lt;To serve man&gt; for dinner.&gt;'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'&lt;To serve man&gt;'</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> greedyRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'&lt;.*&gt;'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo </span><span class="pun">=</span><span class="pln"> greedyRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'&lt;To serve man&gt; for dinner.&gt;'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> mo</span><span class="pun">.</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'&lt;To serve man&gt; for dinner.&gt;'</span></pre>

<p>
	يمكننا ترجمة التعبيرين النمطيين السابقين إلى «طابق قوس بدء زاوية ثم أي شيء ثم قوس إغلاق زاوية»، لكن السلسلة النصية <code>'‎&lt;To serve man&gt; for dinner.&gt;‎'</code> فيها مطابقتين لقوس إغلاق زاوية، ففي النسخة غير الجشعة تطابق بايثون أقصر سلسلة نصية ممكنة <code>'&lt;To serve man&gt;'</code>؛ أما في النسخة الجشعة فتحاول بايثون مطابقة أطول سلسلة نصية ممكنة: <code>'‎&lt;To serve man&gt; for dinner.&gt;‎'</code>.
</p>

<h3 id="-16">
	مطابقة الأسطر الجديدة مع رمز النقطة
</h3>

<p>
	تعلمنا أن النقطة والنجمة ستطابق كل المحارف عدا السطر الجديد، لكن بتمرير وسيط ثاني إلى الدالة <code>re.compile()‎</code> هو <code>re.DOTALL</code> فسنتمكن من استعمال النقطة لمطابقة جميع المحارف بما فيها السطر الجديد:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_83" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> noNewlineRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="str">'.*'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> noNewlineRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'Serve the public trust.\nProtect the innocent.
\nUphold the law.'</span><span class="pun">).</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'Serve the public trust.'</span><span class="pln">


</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> newlineRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="str">'.*'</span><span class="pun">,</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">DOTALL</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> newlineRegex</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'Serve the public trust.\nProtect the innocent.
\nUphold the law.'</span><span class="pun">).</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'Serve the public trust.\nProtect the innocent.\nUphold the law.'</span></pre>

<p>
	التعبير النمطي <code>noNewlineRegex</code> لم نمرر إليه <code>re.DOTALL</code> حين استدعاء <code>re.compile()‎</code> لذا سيطابق النمط كل شيء حتى الوصول إلى محرف السطر الجديد؛ بينما <code>newlineRegex</code> مررنا إليه <code>re.DOTALL</code> حين استدعاء <code>re.compile()‎</code> لذا سيطابق كل شيء، لهذا أعاد استدعاء newlineRegex.search()<code>‎</code> السلسلة النصية كاملة بما فيها الأسطر الجديدة.
</p>

<h2 id="-17">
	مراجعة لرموز التعابير النمطية
</h2>

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

<ul>
	<li>
		يطابق <code>?</code> المجموعة التي تسبقه 0 مرة أو 1 مرة.
	</li>
	<li>
		يطابق <code>*</code> المجموعة التي تسبقه 0 مرة أو أكثر.
	</li>
	<li>
		يطابق <code>+</code> المجموعة التي تسبقه 1 مرة أو أكثر.
	</li>
	<li>
		يطابق <code>{n}</code> المجموعة التي تسبقه n مرة تمامًا.
	</li>
	<li>
		يطابق <code>{‎n,‎}</code> المجموعة التي تسبقه n مرة أو أكثر.
	</li>
	<li>
		يطابق <code>{‎, m}</code> المجموعة التي تسبقه 0 مرة حتى m مرة.
	</li>
	<li>
		يطابق <code>{n, m}</code> المجموعة التي تسبقه n مرة على الأقل و m على الأكثر.
	</li>
	<li>
		تجري <code>‎{n,m}?‎</code> أو ‎<code>*?</code>‎ أو ‎+?<code>‎</code> مطابقة غير جشعة.
	</li>
	<li>
		يطابق <code>‎^spam</code> السلاسل النصية التي تبدأ بالكلمة spam.
	</li>
	<li>
		يطابق <code>spam$‎</code> السلاسل النصية التي تنتهي بالكلمة spam.
	</li>
	<li>
		يطابق الرمز <code>.</code> أي محرف عدا السطر الجديد.
	</li>
	<li>
		تطابق فئة المحارف <code>‎\d</code> و <code>‎\w</code> و <code>‎\s</code> رقمًا أو كلمةً أو فراغًا على التوالي وبالترتيب.
	</li>
	<li>
		تطابق فئة المحارف <code>‎\D</code> و <code>‎\W</code> و <code>‎</code>\S أي شيء عدا أن يكون رقمًا أو كلمةً أو فراغًا على التوالي وبالترتيب.
	</li>
	<li>
		تطابق فئة المحارف <code>[abc]</code> أي شيء بين القوسين المربعين (مثل a أو b أو c).
	</li>
	<li>
		تطابق فئة المحارف <code>[‎^abc]</code> أي شيء ليس بين القوسين المربعين.
	</li>
</ul>

<h2 id="-18">
	المطابقة غير الحساسة لحالة الأحرف
</h2>

<p>
	تطابق التعابير النمطية النص بنفس الحالة المحددة، فمثلًا تطابق التعابير النمطية الآتية سلاسل نصية مختلفة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_85" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> regex1 </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="str">'RoboCop'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> regex2 </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="str">'ROBOCOP'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> regex3 </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="str">'robOcop'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> regex4 </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="str">'RobocOp'</span><span class="pun">)</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_87" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> robocop </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'robocop'</span><span class="pun">,</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">I</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> robocop</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'RoboCop is part man, part machine, all cop.'</span><span class="pun">).</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'RoboCop'</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> robocop</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'ROBOCOP protects the innocent.'</span><span class="pun">).</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'ROBOCOP'</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> robocop</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">'Al, why does your programming book talk about robocop so much?'</span><span class="pun">).</span><span class="pln">group</span><span class="pun">()</span><span class="pln">
</span><span class="str">'robocop'</span></pre>

<h2 id="sub">
	استبدال السلاسل النصية عبر التابع sub()‎
</h2>

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

<p>
	يقبل التابع <code>sub()‎</code> في كائنات <code>Regex</code> معاملين، الأول هو السلسلة النصية التي نريد تبديل المطابقات إليها، والثاني هو السلسلة النصية التي نريد البحث فيها عن مطابقات لتبديلها. يعيد التابع <code>sub()‎</code> سلسلةً نصية بعد تطبيق جميع عمليات الاستبدال:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_89" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> namesRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'Agent \w+'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> namesRegex</span><span class="pun">.</span><span class="pln">sub</span><span class="pun">(</span><span class="str">'CENSORED'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Agent Alice gave the secret documents to Agent Bob.'</span><span class="pun">)</span><span class="pln">
</span><span class="str">'CENSORED gave the secret documents to CENSORED.'</span></pre>

<p>
	قد نحتاج أحيانًا إلى استخدام النص المطابق كجزء من النص الجديد، لذا يمكننا استخدام <code>‎\1</code> و <code>‎</code>\2 و <code>‎\3</code> في الوسيط الأول الممرر إلى التابع <code>sub()‎</code> للوصول إلى المجموعات الفرعية المطابقة.
</p>

<p>
	لنقل أننا نريد أن نخفي أسماء الأشخاص في مثالنا السابق، لكننا نريد إظهار الحرف الأول من اسمهم فقط، فحينها نستطيع استخدام التعبير النمطي <code>Agent (\w)\w*‎</code> وتمرير <code>r'\1‎****'‎</code> كأول معامل إلى التابع sub()<code>‎</code>، وستشير <code>‎\1</code> إلى السلسلة النصية المطابقة من النمط الفرعي الأول، أي المجموعة <code>(‎\w)</code> في التعبير النمطي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_91" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> agentNamesRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'Agent (\w)\w*'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> agentNamesRegex</span><span class="pun">.</span><span class="pln">sub</span><span class="pun">(</span><span class="pln">r</span><span class="str">'\1****'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Agent Alice told Agent Carol that Agent
Eve knew Agent Bob was a double agent.'</span><span class="pun">)</span><span class="pln">
A</span><span class="pun">****</span><span class="pln"> told C</span><span class="pun">****</span><span class="pln"> that E</span><span class="pun">****</span><span class="pln"> knew B</span><span class="pun">****</span><span class="pln"> was a double agent</span><span class="pun">.</span><span class="str">'</span></pre>

<h2 id="-19">
	التعامل مع التعابير النمطية المعقدة
</h2>

<p>
	التعابير النمطية التي تطابق نصًا بسيطًا تكون سهلة الفهم، لكن إذا أردنا مطابقة النصوص المعقدة فستصبح التعابير النمطية معقدة وطويلة، يمكننا التعامل مع هذا الإشكال بالطلب من الدالة re.compile()<code>‎</code> أن تتجاهل الفراغات والتعليقات داخل السلسلة النصية التي تمثل التعبير النمطي، وهذا النمط يسمى verbose mode، ويمكن تفعيله بتمرير <code>re.VERBOSE</code> إلى المعامل الثاني في الدالة <code>re.compile()‎</code>.
</p>

<p>
	فبدلًا من محاولة قراءة تعبير نمطي صعب مثل هذا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_93" style=""><span class="pln">phoneRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'((\d{3}|\(\d{3}\))?(\s|-|\.)?\d{3}(\s|-|\.)\d{4}
(\s*(ext|x|ext.)\s*\d{2,5})?)'</span><span class="pun">)</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_95" style=""><span class="pln">phoneRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'''(
    (\d{3}|\(\d{3}\))?            # رمز المنطقة
    (\s|-|\.)?                    # فاصل
    \d{3}                         # أول 3 أرقام
    (\s|-|\.)                     # فاصل
    \d{4}                         # آخر 4 أرقام
    (\s*(ext|x|ext.)\s*\d{2,5})?  # اللاحقة
    )'''</span><span class="pun">,</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">VERBOSE</span><span class="pun">)</span></pre>

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

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

<h2 id="reignorecaseredotallreverbose">
	استخدام re.IGNORECASE و re.DOTALL و re.VERBOSE
</h2>

<p>
	ماذا لو أردنا استخدام <code>re.VERBOSE</code> لكتابة تعليقات في التعابير النمطية لكننا نريد أن نتجاهل حالة الأحرف أيضًا عبر <code>re.IGNORECASE</code>؟
</p>

<p>
	للأسف لا تقبل الدالة <code>re.compile()‎</code> غير قيمة واحدة كثاني وسيط لها، لكن يمكننا تجاوز هذه المحدودية بجمع القيم <code>re.IGNORECASE</code> و <code>re.DOTALL</code> و <code>re.VERBOSE</code> مع بضعها عبر الخط العمودي <code>|</code> وهو يسمى في هذا السياق بعامل OR الثنائي Bitwise OR.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_97" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> someRegexValue </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="str">'foo'</span><span class="pun">,</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">IGNORECASE </span><span class="pun">|</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">DOTALL</span><span class="pun">)</span></pre>

<p>
	ولو أردنا تضمين الخيارات كلها فنكتب:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_99" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> someRegexValue </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="str">'foo'</span><span class="pun">,</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">IGNORECASE </span><span class="pun">|</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">DOTALL </span><span class="pun">|</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">VERBOSE</span><span class="pun">)</span></pre>

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

<h2 id="-20">
	مشروع: برنامج استخراج أرقام الهواتف وعناوين البريد الإلكتروني
</h2>

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

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

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

<ol>
	<li>
		الحصول على النص من الحافظة.
	</li>
	<li>
		العثور على جميع أرقام الهواتف وعناوين البريد الإلكتروني.
	</li>
	<li>
		لصق الناتج في الحافظة.
	</li>
</ol>

<p>
	يمكنك أن تبدأ الآن بالتفكير كيفية كتابة ذلك في بايثون. سيحتاج برنامجك إلى:
</p>

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

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

<h3 id="1">
	الخطوة 1: إنشاء تعبير نمطي لأرقام الهواتف
</h3>

<p>
	علينا بداية إنشاء تعبير نمطي للبحث عن أرقام الهواتف، لننشِئ ملفًا باسم <code>phoneAndEmail.py</code> ونكتب فيه:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_101" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># phoneAndEmail.py - البحث عن أرقام الهواتف وعناوين البريد في الحافظة</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> pyperclip</span><span class="pun">,</span><span class="pln"> re

phoneRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'''(
    (\d{3}|\(\d{3}\))?                # رمز المنطقة
    (\s|-|\.)?                        # فاصل
    (\d{3})                           # أول 3 أرقام
    (\s|-|\.)                         # فاصل
    (\d{4})                           # آخر 4 أرقام
    (\s*(ext|x|ext.)\s*(\d{2,5}))?    # اللاحقة
    )'''</span><span class="pun">,</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">VERBOSE</span><span class="pun">)</span><span class="pln">

</span><span class="com"># TODO: إنشاء التعبير النمطي لعناوين البريد الإلكتروني</span><span class="pln">

</span><span class="com"># TODO: العثور على المطابقات في الحافظة</span><span class="pln">

</span><span class="com"># TODO: لصق الناتج في الحافظة</span></pre>

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

<p>
	يبدأ رقم الهاتف برمز منطقة اختياري، لذا نجعل المجموعة الفرعية التي تدل على رمز المنطقة اختياريةً بإضافة علامة استفهام <code>?</code>. ولأن رمز المنطقة يمكن أن يكون 3 أرقام (أي ‎\d{3}<code>‎</code>) أو 3 أرقام ضمن أقواس (أي <code>‎\(\d{3}\)‎</code>) فاستعملنا الخط العمودي | للفصل بينهما. لاحظ أننا استطعنا إضافة التعليقات إلى التعبير النمطي متعدد الأسطر لكي نتذكر ماذا يفعل كل سطر.
</p>

<p>
	يمكن أن يكون الفاصل في أرقام الهواتف فراغًا ‎\s أو شرطة - أو نقطة .، لذا فصلنا بين هذه الاحتمالات بخط عمودي.
</p>

<p>
	بقية أقسام التعبير النمطي واضحة وسهلة: 3 أرقام، يتبعها فاصل، يتبعها 4 أرقام، وآخر قسم هو اللاحقة الاختيارية التي تبدأ بأي عدد من الفراغات يليها الكلمة ext أو x أو ext.‎، ويليها رقمين إلى 5 أرقام.
</p>

<p>
	ملاحظة: من السهل أن نخلط بين التعابير النمطية التي تحتوي على مجموعات عبر استخدام الأقواس <code>()</code>، وبين الأقواس المُهربة <code>‎</code>)‎ و ‎(<code>‎</code>. تذكر أن تتأكد أنك تستخدم النوع الصحيح من الأقواس إن حصلت على رسالة خطأ تشير إلى قوسٍ ناقص.
</p>

<h3 id="2">
	الخطوة 2: إنشاء تعبير نمطي لعناوين البريد الإلكتروني
</h3>

<p>
	علينا الآن إنشاء تعبير نمطي لمطابقة عناوين البريد الإلكتروني:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_103" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># phoneAndEmail.py - البحث عن أرقام الهواتف وعناوين البريد في الحافظة</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> pyperclip</span><span class="pun">,</span><span class="pln"> re

phoneRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'''(
--مقتطع--

# إنشاء التعبير النمطي لعناوين البريد الإلكتروني
emailRegex = re.compile(r'''</span><span class="pun">(</span><span class="pln">
  </span><span class="pun">➊</span><span class="pln"> </span><span class="pun">[</span><span class="pln">a</span><span class="pun">-</span><span class="pln">zA</span><span class="pun">-</span><span class="pln">Z0</span><span class="pun">-</span><span class="lit">9.</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"> </span><span class="pun">@</span><span class="pln">                      </span><span class="com"># @ إشارة</span><span class="pln">
  </span><span class="pun">➌</span><span class="pln"> </span><span class="pun">[</span><span class="pln">a</span><span class="pun">-</span><span class="pln">zA</span><span class="pun">-</span><span class="pln">Z0</span><span class="pun">-</span><span class="lit">9.</span><span class="pun">-]+</span><span class="pln">         </span><span class="com"># اسم النطاق</span><span class="pln">
    </span><span class="pun">(</span><span class="pln">\.</span><span class="pun">[</span><span class="pln">a</span><span class="pun">-</span><span class="pln">zA</span><span class="pun">-</span><span class="pln">Z</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="pln">       </span><span class="com"># اللاحقة</span><span class="pln">
    </span><span class="pun">)</span><span class="str">''', re.VERBOSE)

# TODO: العثور على المطابقات في الحافظة

# TODO: لصق الناتج في الحافظة</span></pre>

<p>
	يكون اسم المستخدم جزءًا من البريد الإلكتروني ➊، وفيه محارف واحدة أو أكثر مما يلي: الأحرف الكبيرة والصغيرة، والأرقام، والنقطة، والشرطة السفلية، وإشارة النسبة المئوية، وإشارة زائد، وشرطة عادية. يمكننا جمع كل ما سبق في فئة المحارف الآتية <code>[a-zA-Z0-9‎._%+-‎]</code>.
</p>

<p>
	يفصل بين اسم المستخدم والنطاق برمز @ ➋؛ ولا يسمح اسم النطاق بنفس المحارف التي يسمح بها اسم المستخدم، ولذا يجب أن ننشِئ فئة محارف فيها الأرقام والأحرف والنقط والشرطات <code>[a-zA-Z0-9‎.-‎]</code> ➌.
</p>

<p>
	آخر جزء هو اللاحقة، مثل ‎.com (يسمى تقنيًا بالنطاق في أعلى مستوى top-level domain) الذي هو رمز النقطة ويلي أي شيء، ويفترض أن يكون بين 2 و 4 محارف.
</p>

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

<h3 id="3">
	الخطوة 3: العثور على جميع المطابقات في الحافظة
</h3>

<p>
	أصبح لدينا الآن التعابير النمطية التي ستطابق أرقام الهواتف وعناوين البريد الإلكتروني عبر الوحدة <code>re</code> في بايثون، واستطعنا الوصول إلى محتويات الحافظة عبر الدالة <code>paste()‎</code> في الوحدة <code>pyperclip</code>. نحتاج الآن إلى استخدام التابع <code>findall()‎</code> للكائن <code>Regex</code> لإعادة قائمة من الصفوف. تأكد أن برنامجك يشبه البرنامج الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_105" style=""><span class="pln">   </span><span class="com">#! python3</span><span class="pln">
   </span><span class="com"># phoneAndEmail.py - البحث عن أرقام الهواتف وعناوين البريد في الحافظة</span><span class="pln">

   </span><span class="kwd">import</span><span class="pln"> pyperclip</span><span class="pun">,</span><span class="pln"> re

   phoneRegex </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">r</span><span class="str">'''(
--مقتطع--


   # العثور على المطابقات في الحافظة
   text = str(pyperclip.paste())

➊ matches = []
➋ for groups in phoneRegex.findall(text):
       phoneNum = '-'.join([groups[1], groups[3], groups[5]])
       if groups[8] != '':
           phoneNum += ' x' + groups[8]
       matches.append(phoneNum)
➌ for groups in emailRegex.findall(text):
       matches.append(groups[0])

   # TODO: لصق الناتج في الحافظة</span></pre>

<p>
	هنالك صف لكل مطابقة ناتجة، وكل صف يحتوي على السلاسل النصية في كل مجموعة في التعبير النمطي، تذكر أن المجموعة 0 تطابق كامل التعبير النمطي، لذا ما يهمنا من الناتج هو المجموعة في الفهرس 0.
</p>

<p>
	سنخزن المطابقات في قائمة باسم <code>matches</code> ➊، وسنبدأ برنامجنا بقائمة فارغة، ثم لدينا حلقتَي for. ففي الحلقة الخاصة بالبريد الإلكتروني نضيف محتويات المجموعة 0 إلى القائمة <code>matches</code> ➌؛ أما في الحلقة الخاصة بأرقام الهواتف فلا نريد أن نضيف ناتج المجموعة 0 إلى القائمة. صحيحٌ أن برنامجنا يستطيع مطابقة أرقام الهواتف بأكثر من صيغة، لكننا نريد إضافة أرقام الهواتف بصيغة واحدة معيارية، لذا ننشِئ المتغير <code>phoneNum</code> الذي يحتوي على قيمة المجموعات 1 و 3 و 5 و 8 من النص المطابق، وهي تمثل رقم المنطقة، وأول 3 أرقام، وآخر 4 أرقام، واللاحقة على التوالي وبالترتيب.
</p>

<h3 id="4">
	الخطوة 4: جمع المطابقات في سلسلة نصية ونسخها إلى الحافظة
</h3>

<p>
	أصبح لدينا الآن عناوين البريد الإلكتروني وأرقام الهواتف كقائمة من السلاسل النصية المخزنة في <code>matches</code>، إذا أردنا نسخ هذه القائمة إلى الحافظة فسنستعمل الدالة pyperclip.copy()<code>‎</code> التي تقبل سلسلة نصية، لكن المطابقات موجودة لدينا في قائمة، لذا نحن بحاجة إلى استخدام التابع join()<code>‎</code> على القائمة <code>matches</code>.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_107" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># phoneAndEmail.py - البحث عن أرقام الهواتف وعناوين البريد في الحافظة</span><span class="pln">

</span><span class="pun">--مقتطع--</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> groups </span><span class="kwd">in</span><span class="pln"> emailRegex</span><span class="pun">.</span><span class="pln">findall</span><span class="pun">(</span><span class="pln">text</span><span class="pun">):</span><span class="pln">
    matches</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">groups</span><span class="pun">[</span><span class="lit">0</span><span class="pun">])</span><span class="pln">

</span><span class="com"># Copy results to the clipboard.</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">matches</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">
    pyperclip</span><span class="pun">.</span><span class="pln">copy</span><span class="pun">(</span><span class="str">'\n'</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">matches</span><span class="pun">))</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Copied to clipboard:'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'\n'</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">matches</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="str">'No phone numbers or email addresses found.'</span><span class="pun">)</span></pre>

<h3 id="-21">
	تشغيل البرنامج
</h3>

<p>
	للتجربة، افتح المتصفح وتوجه إلى صفحة تواصل معنا من موقع <a href="https://nostarch.com/contactus" rel="external nofollow">nostarch.com</a>، ثم حددها كلها بالضغط على Ctrl+A ثم انسخها إلى الحافظة Ctrl+C، ثم شغل البرنامج. يجب أن يكون الناتج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7868_109" style=""><span class="typ">Copied</span><span class="pln"> to clipboard</span><span class="pun">:</span><span class="pln">
</span><span class="lit">800</span><span class="pun">-</span><span class="lit">420</span><span class="pun">-</span><span class="lit">7240</span><span class="pln">
</span><span class="lit">415</span><span class="pun">-</span><span class="lit">863</span><span class="pun">-</span><span class="lit">9900</span><span class="pln">
</span><span class="lit">415</span><span class="pun">-</span><span class="lit">863</span><span class="pun">-</span><span class="lit">9950</span><span class="pln">
info@nostarch</span><span class="pun">.</span><span class="pln">com
media@nostarch</span><span class="pun">.</span><span class="pln">com
academic@nostarch</span><span class="pun">.</span><span class="pln">com
info@nostarch</span><span class="pun">.</span><span class="pln">com</span></pre>

<h3 id="-22">
	أفكار لمشاريع مشابهة
</h3>

<p>
	هنالك تطبيقات كثيرة لعملية مطابقة أنماط من النص (واستبدلها عبر التابع sub()‎)، فمثلًا يمكنك:
</p>

<p>
	العثور على جميع <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/" rel="">روابط URL</a> التي تبدأ بالسابقة http://‎ أو https://‎. العثور على التواريخ بصيغها المختلفة مثل 3/14/2022 أو 03-14-2022 أو 2022/3/14 وتبديلها إلى صيغة واحدة قياسية موحدة. إزالة البيانات الحساسة مثل أرقام البطاقات البنكية من المستندات. العثور على الأخطاء الشائعة مثل الفراغات المكررة بين الكلمات، أو الكلمات المكررة خطأً، أو علامات الترقيم المكررة.
</p>

<h2 id="-23">
	الخلاصة
</h2>

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

<p>
	تأتي الوحدة <code>re</code> مع أساس لغة بايثون، وتسمح لنا ببناء كائنات <code>Regex</code>، التي تمتلك عددًا من التوابع: التابع <code>search()‎</code> للبحث عن مطابقة واحدة، والتابع <code>findall()‎</code> للعثور على جميع المطابقات، والتابع <code>sub()‎</code> لإجراء عمليات البحث والاستبدال.
</p>

<p>
	ستجد المزيد من المعلومات في توثيق بايثون الرسمي عن التعابير النمطية، وفي موقع regular-expressions.info.
</p>

<h2 id="-24">
	مشاريع تدريبية
</h2>

<p>
	لكي تتدرب، اكتب برامج لتنفيذ المهام الآتية.
</p>

<h3 id="-25">
	التحقق من التاريخ
</h3>

<p>
	اكتب تعبيرًا نمطيًا يستطيع التعرف على التواريخ بالصيغة DD/MM/YYYY، افترض أن الأيام تتراوح بين 01 إلى 31، والأشهر من 01 إلى 12، والسنوات من 1000 إلى 2999. لاحظ أنه إذا كان اليوم أو الشهر متألف من رقم واحد فيجب أن يسبق بصفر 0.
</p>

<p>
	لا حاجة أن يتعرف التعبير النمطي على الأرقام الصحيحة لكل شهر من أشهر السنة، أو إذا كانت السنوات كبيسة؛ فلا بأس أن يقبل تاريخًا مثل 31/02/2022 أو 31/04/2022.
</p>

<p>
	خزن السلاسل النصية الناتج في متغيرات باسم month و day و year، ثم اكتب شيفرة تتحقق إن كان التاريخ صالحًا، فأشهر نسيان/أبريل وحزيران/يونيو وأيلول/سبتمبر وتشرين الثاني/نوفمبر لها 30 يومًا، وشهر شباط/فبراير له 28 يومًا، وبقية الأشهر 31 يومًا.
</p>

<p>
	يكون طول شهر شباط/فبراير 29 يومًا في السنوات الكبيسة، والسنة الكبيرة هي كل سنة تكون قابلة للقسمة على 4، عدا السنوات القابلة للقسمة على 100؛ ما لم تكن السنة قابلة للقسم على 400. لاحظ أن هذه العمليات الحسابية تجعل من المستحيل كتابة تعبير نمطي يمكنه فعل كل ذلك.
</p>

<h3 id="-26">
	التحقق من كلمة مرور قوية
</h3>

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

<p>
	قد تحتاج إلى اختبار كلمة المرور على أكثر من تعبير نمطي للتأكد من قوتها.
</p>

<h3 id="strip">
	نسخة من الدالة strip()‎ باستخدام التعابير النمطية
</h3>

<p>
	اكتب دالةً تقبل سلسلةً نصيةً وتفعل فيها كما تفعله الدالة <code>strip()‎</code> التي تعلمناها في المقال السابق.
</p>

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

<p>
	ترجمة -بتصرف- للفصل <a href="https://automatetheboringstuff.com/2e/chapter7/" rel="external nofollow">Pattern Matching With Regular Expressions</a> من كتاب <a href="https://automatetheboringstuff.com/#toc" rel="external nofollow">Automate the Boring Stuff with Python</a>.
</p>

<h2 id="-27">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/python/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2344/" rel="">معالجة النصوص باستخدام لغة بايثون python</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/python/%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-lists-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r2339/" rel="">القوائم Lists في لغة بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2322/" rel="">تهيئة بيئة العمل في بايثون Python</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2345</guid><pubDate>Wed, 19 Jun 2024 15:08:03 +0000</pubDate></item><item><title>&#x645;&#x639;&#x627;&#x644;&#x62C;&#x629; &#x627;&#x644;&#x646;&#x635;&#x648;&#x635; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x644;&#x63A;&#x629; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646; Python</title><link>https://academy.hsoub.com/programming/python/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2344/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_06/----Strings--.png.f92129978a96f98654778a48a4f6514d.png" /></p>
<p>
	النصوص هي أكثر أنواع البيانات التي ستتعامل معها في برنامجك. لقد تعلمت كيفية جمع سلسلتين نصيتين مع بعضها عبر العامل <code>+</code>، لكنك تستطيع أكثر من ذلك بكثير؛ إذ تستطيع استخراج <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> فرعية، وإضافة وحذف الفراغات، وتحويل الأحرف إلى أحرف كبيرة أو صغيرة، والتحقق من تنسيق السلاسل تنسيقًا صحيحًا؛ وتستطيع أيضًا كتابة برنامج بايثون للوصول إلى الحافظة في حاسوبك لنسخ ولصق النصوص.
</p>

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

<h2 id="">
	التعامل مع السلاسل النصية
</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> بالكتابة والطباعة والوصول إلى السلاسل النصية في برامجنا.
</p>

<h3 id="-1">
	السلاسل النصية المجردة
</h3>

<p>
	كتابة القيم النصية في شيفرة بايثون هو أمر بالغ السهولة: نبدأ وننتهي بعلامة اقتباس مفردة.
</p>

<p>
	لكن ماذا سيحدث لو أردنا استخدام علامة اقتباس داخل السلسلة النصية؟ إذا كتبنا <code>‎'That is Alice's cat.'‎</code> فسيحدث خطأ لأن بايثون ستظن أن السلسلة النصية قد انتهت بعد Alice وبقية السطر s cat.'<code>‎</code> هي شيفرة غير صالحة في بايثون.
</p>

<p>
	لحسن الحظ هنالك عدة طرائق لكتابة السلاسل النصية.
</p>

<h4 id="-2">
	علامات الاقتباس المزدوجة
</h4>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_10" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="str">"That is Alice's cat."</span></pre>

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

<h4 id="-3">
	محارف التهريب
</h4>

<p>
	تسمح لنا محارف التهريب escape characters باستخدام محارف ليس من الممكن إدراجها مباشرةً في السلسلة النصية.
</p>

<p>
	يتألف محرف التهريب من خط مائل خلفي backslash <code>\</code> متبوعًا بأحد المحارف التي نريد إضافتها إلى السلسلة النصية؛ وصحيحٌ أن اسمه هو «محرف» التهريب، لكن يتألف من محرفين ويشار إليه عادةً بصيغة المفرد escape character.
</p>

<p>
	فمثلًا محرف التهريب لعلامة الاقتباس المفردة هو ‎\'<code>‎</code> وذب الشيفرة الآتية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_12" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Say hi to Bob\'s brother.'</span></pre>

<p>
	ولأننا وضعنا خط مائل خلفي قبل علامة الاقتباس المفردة في <code>Bob\'s</code> فستعلم بايثون أننا لا نقصد أن ننهي السلسلة النصية. تسمح لنا محارف التهريب<code>\'</code> و <code>\"</code> بوضع علامات الاقتباس داخل السلاسل النصية المحاطة بعلامات اقتباس مفردة ومزدوجة على الترتيب. الجدول 6-1 يوضح بعض محارف التهريب التي تستطيع استخدامها.
</p>

<p>
	فيما يلي محارف التهريب:
</p>

<ul>
	<li>
		<code>‎\'‎</code>: علامة اقتباس مفردة
	</li>
	<li>
		‎\"<code>‎</code>: علامة اقتباس مزدوجة
	</li>
	<li>
		<code>‎\t</code>: علامة الجدولة tab
	</li>
	<li>
		<code>‎\n</code>: سطر جديد newline
	</li>
	<li>
		<code>\\</code>: خط مائل خلفي
	</li>
</ul>

<p>
	جرب السلسلة النصية الآتية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_14" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="str">"Hello there!\nHow are you?\nI\'m doing fine."</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Hello</span><span class="pln"> there</span><span class="pun">!</span><span class="pln">
</span><span class="typ">How</span><span class="pln"> are you</span><span class="pun">?</span><span class="pln">
I</span><span class="str">'m doing fine.</span></pre>

<h4 id="-4">
	السلاسل النصية الخام
</h4>

<p>
	يمكنك وضع الحرف r قبل علامة الاقتباس في بداية السلسلة النصية لجعلها سلسلة نصية خام. السلسلة النصية الخام raw string تتجاهل جميع محارف التهريب وتظهر جميع الخطوط المائلة الخلفية كما هي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_16" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">r</span><span class="str">'That is Carol\'s cat.'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">That</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="typ">Carol</span><span class="pln">\'s cat</span><span class="pun">.</span></pre>

<p>
	ولأنها سلسلة نصية خام فستعدّ بايثون الخط الخلفي المائل على أنه جزء من السلسلة النصية وليس جزءًا من محرف التهريب. يمكن أن تكون السلاسل النصية الخام مفيدةً إن كانت تكتب سلاسل نصية فيها عدد من الخطوط المائلة الخلفية، مثل مسارات الملفات في نظام ويندوز <code>r'C:\Users\Al\Desktop'‎</code> أو التعابير النمطية regular expressions المشروحة في المقال القادم.
</p>

<h4 id="-5">
	السلاسل النصية متعددة الأسطر بعلامات اقتباس ثلاثية
</h4>

<p>
	صحيحٌ أن بإمكاننا استخدام محرف التهريب ‎\n لطابعة سطر جديد داخل سلسلة نصية، لكن من الأسهل استخدام السلاسل النصية متعددة الأسطر. تبدأ السلسلة النصية متعددة الأسطر في بايثون بثلاث علامات اقتباس مفردة أو مزدوجة، وستعد جميع علامات الاقتباس ومسافات الجدولة tabs والأسطر الجديدة على أنها جزءٌ من السلسلة النصية المحاطة بعلامات اقتباس ثلاثية.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_18" style=""><span class="kwd">print</span><span class="pun">(</span><span class="str">'''Dear Alice,

Eve's cat has been arrested for catnapping, cat burglary, and extortion.

Sincerely,
Bob'''</span><span class="pun">)</span></pre>

<p>
	احفظ ما سبق في ملف باسم <code>catnapping.py</code> وشغله:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_20" style=""><span class="typ">Dear</span><span class="pln"> </span><span class="typ">Alice</span><span class="pun">,</span><span class="pln">

</span><span class="typ">Eve</span><span class="str">'s cat has been arrested for catnapping, cat burglary, and extortion.

Sincerely,
Bob</span></pre>

<p>
	لاحظ أن علامة الاقتباس المفردة في <code>Eve's</code> لا تحتاج إلى تهريب، فتهريب علامات الاقتباس المفردة والمزدوجة هو أمرٌ اختياري حين استخدام السلاسل النصية متعددة الأسطر. السلسلة النصية الموجودة في دالة print()<code>‎</code> الآتية تكافئ المثال السابق دون استخدام السلاسل النصية متعددة الأسطر:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_22" style=""><span class="kwd">print</span><span class="pun">(</span><span class="str">'Dear Alice,\n\nEve\'s cat has been arrested for catnapping, cat
burglary, and extortion.\n\nSincerely,\nBob'</span><span class="pun">)</span></pre>

<h4 id="-6">
	التعليقات متعددة الأسطر
</h4>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_24" style=""><span class="str">"""This is a test Python program.
Written by Al Sweigart al@inventwithpython.com

This program was designed for Python 3, not Python 2.
"""</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> spam</span><span class="pun">():</span><span class="pln">
    </span><span class="str">"""This is a multiline comment to help
    explain what the spam() function does."""</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hello!'</span><span class="pun">)</span></pre>

<h3 id="-7">
	فهرسة وتقسيم السلاسل النصية
</h3>

<p>
	تستعمل السلاسل النصية الفهارس ويمكن تقسيمها كما في القوائم lists. يمكنك أن تعدّ السلسلة النصية <code>‎'Hello, world!'‎</code> على أنها قائمة وكل حرف فيها يمثل عنصرًا في تلك القائمة مع فهرس مرتبط به.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_26" style=""><span class="str">'   H   e   l   l   o   ,       w   o   r   l    d    !   '</span><span class="pln">
    </span><span class="lit">0</span><span class="pln">   </span><span class="lit">1</span><span class="pln">   </span><span class="lit">2</span><span class="pln">   </span><span class="lit">3</span><span class="pln">   </span><span class="lit">4</span><span class="pln">   </span><span class="lit">5</span><span class="pln">   </span><span class="lit">6</span><span class="pln">   </span><span class="lit">7</span><span class="pln">   </span><span class="lit">8</span><span class="pln">   </span><span class="lit">9</span><span class="pln">   </span><span class="lit">10</span><span class="pln">   </span><span class="lit">11</span><span class="pln">   </span><span class="lit">12</span></pre>

<p>
	لاحظ تضمين الفراغ وإشارة التعجب، وسيكون عدد الأحرف هو 13، بدءًا من الحرف H في الفهرس 0 إلى الحرف ! في الفهرس 12.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_28" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Hello, world!'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
</span><span class="str">'H'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[</span><span class="lit">4</span><span class="pun">]</span><span class="pln">
</span><span class="str">'o'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[-</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
</span><span class="str">'!'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</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="pln">
</span><span class="str">'Hello'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[:</span><span class="lit">5</span><span class="pun">]</span><span class="pln">
</span><span class="str">'Hello'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[</span><span class="lit">7</span><span class="pun">:]</span><span class="pln">
</span><span class="str">'world!'</span></pre>

<p>
	إذا حددت فهرسًا فستحصل على المحرف الموجود في ذاك الموضع في السلسلة النصية، وإذا حددت مجالًا من فهرسٍ ما إلى آخر فسيُضمَّن المحرف الموجود في فهرس البداية ولن يضمن المحرف الموجود في فهرس النهاية، ولذا إذا كان لدينا المتغير <code>spam</code> الذي فيه ‎'Hello, world!'<code>‎</code> فإن <code>spam[0:5]‎</code> هو <code>'Hello'</code>؛ فالسلسلة النصية الجزئية التي ستحصل عليها من <code>spam[0:5]‎</code> ستتضمن كل محرف موجود في المجال <code>spam[0]‎</code> حتى <code>spam[4]‎</code> ولن تحتوي الفاصلة الموجودة في الفهرس 5 ولا الفراغ في المحرف 6.
</p>

<p>
	هذا السلوك يشبه سلوك الدالة <code>range(5)‎</code> التي ستؤدي -حين استعمالها مع <code>for</code>- إلى المرور على الأرقام حتى الرقم 5 دون تضمينه.
</p>

<p>
	لاحظ أن تقسيم السلاسل النصية لا يغير السلسلة النصية الأصلية، ويمكننا حفظ القيمة الناتجة في متغير منفصل:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_30" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Hello, world!'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> fizz </span><span class="pun">=</span><span class="pln"> spam</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="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> fizz
</span><span class="str">'Hello'</span></pre>

<p>
	بتقسيم السلسلة النصية ثم تخزينها في متغير آخر فسنتمكن من الوصول إلى السلسلة النصية الأصلية والسلسلة النصية المقتطعة بسهولة.
</p>

<h4 id="innotin">
	العوامل in و not in مع السلاسل النصية
</h4>

<p>
	يمكن استخدام العاملين <code>in</code> و <code>not in</code> مع السلاسل النصية كما في القوائم lists. التعبير البرمجي الذي فيه سلسلتين نصيتين مجموعٌ بينها بالعامل in أو not in سينتج القيمة المنطقية <code>True</code> أو <code>False</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_32" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="str">'Hello, World'</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="str">'Hello'</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'HELLO'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="str">'Hello, World'</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">''</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="str">'spam'</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'cats'</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="str">'cats and dogs'</span><span class="pln">
</span><span class="kwd">False</span></pre>

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

<h3 id="-8">
	وضع السلاسل النصية داخل سلاسل نصية أخرى
</h3>

<p>
	من الشائع في البرمجة وضع سلسلة نصية داخل سلسلة نصية أخرى، واستعملنا حتى الآن العامل <code>+</code> لجمع السلاسل النصية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_34" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Al'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> age </span><span class="pun">=</span><span class="pln"> </span><span class="lit">4000</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello, my name is '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> name </span><span class="pun">+</span><span class="pln"> </span><span class="str">'. I am '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">age</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">' years old.'</span><span class="pln">
</span><span class="str">'Hello, my name is Al. I am 4000 years old.'</span></pre>

<p>
	لكن ذلك يتطلب كتابةً كثيرة، ومن الأسهل أن ندس السلاسل النصية داخل بعضها string interpolation، وبهذه الطريقة نستعمل العامل ‎%s داخل السلاسل النصية كمؤشر لكي يستبدل مسبقًا إلى القيم التي تلي السلسلة النصية.
</p>

<p>
	إحدى ميزات استخدام هذه الطريقة هو عدم حاجتنا إلى استدعاء الدالة <code>str()‎</code> لتحويل القيم إلى سلاسل نصية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_36" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Al'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> age </span><span class="pun">=</span><span class="pln"> </span><span class="lit">4000</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'My name is %s. I am %s years old.'</span><span class="pln"> </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"> age</span><span class="pun">)</span><span class="pln">
</span><span class="str">'My name is Al. I am 4000 years old.'</span></pre>

<p>
	أضافت بايثون 3.6 ما يسمى بالسلاسل النصية المنسقة <code>f-strings</code>، وهي تشبه دس السلاسل النصية لكنها تتيح إضافة التعابير البرمجية بين قوسين مجعدين مباشرةً؛ تذكر أن تضيف الحرف f قبل علامة الاقتباس الابتدائية في السلسلة النصية المنسقة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_38" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Al'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> age </span><span class="pun">=</span><span class="pln"> </span><span class="lit">4000</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> f</span><span class="str">'My name is {name}. Next year I will be {age + 1}.'</span><span class="pln">
</span><span class="str">'My name is Al. Next year I will be 4001.'</span></pre>

<p>
	إذا لم تتذكر تضمين الحرف f قبل علامة الاقتباس فستعامل الأقواس على أنها جزء من السلسلة النصية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_40" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'My name is {name}. Next year I will be {age + 1}.'</span><span class="pln">
</span><span class="str">'My name is {name}. Next year I will be {age + 1}.'</span></pre>

<h3 id="-9">
	توابع مفيدة للتعامل مع السلاسل النصية
</h3>

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

<h4 id="upperlowerisupperislower">
	التوابع upper()‎ و lower()‎ و isupper()‎ و islower()‎
</h4>

<p>
	يعيد التابعان <code>upper()‎</code> و lower()<code>‎</code> سلسلةً نصيةً جديدةً تحوَّل فيها أحرف السلسلة النصية الأصلية إلى حالة الأحرف الكبيرة أو الصغيرة على التوالي. أما المحارف غير النصية أو غير اللاتينية فتبقى كما هي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_42" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Hello, world!'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">upper</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="str">'HELLO, WORLD!'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">lower</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="str">'hello, world!'</span></pre>

<p>
	لاحظ أن هذان التابعان لا يغيران السلسلة النصية الأصلية وإنما يعيدان سلسلةً نصيةً جديدةً. إذا أردت تعديل السلسلة النصية الأصلية فعليك استدعاء التابع <code>upper()‎</code> أو <code>lower()‎</code> على السلسلة النصية ثم إسناد الناتج مباشرةً إلى المتغير الذي يحتوي على السلسلة النصية الأصلية؛ أي أننا سنكتب شيئًا يشبه <code>spam = spam.upper()‎</code> لتعديل السلسلة النصية المخزنة في المتغير <code>spam</code> بدلًا من كتابة <code>spam.upper()‎</code> فقط، وهذا يشبه حالة وجود متغير اسمه <code>eggs</code> يحتوي القيمة 10، فكتابة التعبير البرمجي <code>eggs + 3</code> لا يؤدي إلى تغيير القيمة المخزنة في المتغير <code>eggs</code> مباشرة، وإنما علينا كتابة <code>eggs = eggs + 3</code>.
</p>

<p>
	التابعان upper()<code>‎</code> و lower()<code>‎</code> مفيدان إن أردنا مقارنة سلسلتين نصيتين مقارنةً غير حساسةٍ لحالة الأحرف. فمثلًا السلسلتان النصيتان <code>'great'</code> و <code>'GREat'</code> غير متساويتين؛ لكن قد لا يهمنا في بعض الحالات التي نطلب فيها مدخلات المستخدم إن كان قد كتب <code>Great</code> أم <code>GREAT</code> أم <code>gREAt</code>. انظر المثال الآتي الذي نحول فيه السلسلة النصية إلى حالة الأحرف الصغيرة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_44" style=""><span class="kwd">print</span><span class="pun">(</span><span class="str">'How are you?'</span><span class="pun">)</span><span class="pln">
feeling </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> feeling</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"> </span><span class="str">'great'</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'I feel great too.'</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="str">'I hope the rest of your day is good.'</span><span class="pun">)</span></pre>

<p>
	حينما تشغل البرنامج السابق فسيظهر لك سؤال، وإذا أدخلت الكلمة <code>great</code> بأي شكل من الأشكال فستظهر لك العبارة ‎'I feel great too.'<code>‎</code>. من المفيد جدًا إضافة آلية للتعامل مع اختلاف حالات الأحرف في مدخلات المستخدم في برامجك، إذ سيسهل ذلك استخدامها كثيرًا.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_46" style=""><span class="typ">How</span><span class="pln"> are you</span><span class="pun">?</span><span class="pln">
</span><span class="typ">GREat</span><span class="pln">
I feel great too</span><span class="pun">.</span></pre>

<p>
	يعيد التابعان <code>isupper()‎</code> و <code>islower()‎</code> قيمةً منطقية <code>True</code> إن كانت السلسلة النصية تحتوي على حرف واحد على الأقل وكان ذاك الحرف كبيرًا أو صغيرًا على التوالي وبالترتيب؛ وإلا فستعيد القيمة <code>False</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_48" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Hello, world!'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">islower</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">isupper</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'HELLO'</span><span class="pun">.</span><span class="pln">isupper</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'abc12345'</span><span class="pun">.</span><span class="pln">islower</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'12345'</span><span class="pun">.</span><span class="pln">islower</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'12345'</span><span class="pun">.</span><span class="pln">isupper</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">False</span></pre>

<p>
	ولأن القيمة المعادة من التابعين <code>upper()‎</code> و <code>lower()‎</code> هي سلاسل نصية، فيمكننا استدعاء توابع التعامل مع السلاسل النصية على القيم المعادة من تلك التوابع مباشرةً، وتبدو هذه التعابير البرمجية على أنها سلسلة من التوابع وراء بعضها كما في المثال الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_50" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello'</span><span class="pun">.</span><span class="pln">upper</span><span class="pun">()</span><span class="pln">
</span><span class="str">'HELLO'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello'</span><span class="pun">.</span><span class="pln">upper</span><span class="pun">().</span><span class="pln">lower</span><span class="pun">()</span><span class="pln">
</span><span class="str">'hello'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello'</span><span class="pun">.</span><span class="pln">upper</span><span class="pun">().</span><span class="pln">lower</span><span class="pun">().</span><span class="pln">upper</span><span class="pun">()</span><span class="pln">
</span><span class="str">'HELLO'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'HELLO'</span><span class="pun">.</span><span class="pln">lower</span><span class="pun">()</span><span class="pln">
</span><span class="str">'hello'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'HELLO'</span><span class="pun">.</span><span class="pln">lower</span><span class="pun">().</span><span class="pln">islower</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">True</span></pre>

<h4 id="isx">
	مجموعة توابع isX()‎
</h4>

<p>
	بالإضافة إلى التابعين <code>islower()‎</code> و <code>isupper()‎</code> هنالك عدد من التوابع التي يبدأ اسمها بالكلمة is، وتعيد تلك التوابع قيمةً منطقية التي تشرح طبيعة السلسلة النصية. هذه بعض تلك التوابع:
</p>

<ul>
	<li>
		<code>isalpha()‎</code> يعيد <code>True</code> إذا احتوت السلسلة النصية على أحرف عادية فقط ولم تكن فارغة.
	</li>
	<li>
		<code>isalnum()‎</code> يعيد <code>True</code> إذا احتوت السلسلة النصية على أحرف عادية وأرقام فقط ولم تكن فارغة.
	</li>
	<li>
		<code>isdecimal()‎</code> يعيد <code>True</code> إذا احتوت السلسلة النصية على أرقام فقط ولم تكن فارغة.
	</li>
	<li>
		<code>isspace()‎</code> يعيد <code>True</code> إذا احتوت السلسلة النصية على فراغات عادية ومسافات جدولة tabs وأسطر جديدة newlines فقط ولم تكن فارغة.
	</li>
	<li>
		<code>istitle()‎</code> يعيد <code>True</code> إذا بدأت السلسلة النصية بحرف كبير متبوعٌ بمجموعة من الأحرف الصغيرة.
	</li>
</ul>

<p>
	لنجرب تلك التوابع عمليًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_52" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'hello'</span><span class="pun">.</span><span class="pln">isalpha</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'hello123'</span><span class="pun">.</span><span class="pln">isalpha</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'hello123'</span><span class="pun">.</span><span class="pln">isalnum</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'hello'</span><span class="pun">.</span><span class="pln">isalnum</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'123'</span><span class="pun">.</span><span class="pln">isdecimal</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'    '</span><span class="pun">.</span><span class="pln">isspace</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'This Is Title Case'</span><span class="pun">.</span><span class="pln">istitle</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'This Is Title Case 123'</span><span class="pun">.</span><span class="pln">istitle</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'This Is not Title Case'</span><span class="pun">.</span><span class="pln">istitle</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'This Is NOT Title Case Either'</span><span class="pun">.</span><span class="pln">istitle</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">False</span></pre>

<p>
	تفيد توابع السلاسل النصية <code>isX()‎</code> حينما نريد التحقق من مدخلات المستخدم، فالبرنامج الآتي يطلب من المستخدم إدخال عمره وكلمة مرور صالحة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_54" style=""><span class="kwd">while</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Enter your age:'</span><span class="pun">)</span><span class="pln">
    age </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> age</span><span class="pun">.</span><span class="pln">isdecimal</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="str">'Please enter a number for your age.'</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">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Select a new password (letters and numbers only):'</span><span class="pun">)</span><span class="pln">
    password </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> password</span><span class="pun">.</span><span class="pln">isalnum</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="str">'Passwords can only have letters and numbers.'</span><span class="pun">)</span></pre>

<p>
	طلبنا من المستخدم في أول حلقة <code>while</code> أن يدخل عمره، ونخزنه في المتغير <code>age</code>. إذا كانت قيمة <code>age</code> هي قيمة عددية صحيحة، فسنخرج من أول <a href="https://wiki.hsoub.com/Python/while" rel="external">حلقة while</a> وندخل في الثانية التي تسأله عن كلمة المرور. وإلا فسنسأل المستخدم عن عمره مجددًا.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_57" style=""><span class="typ">Enter</span><span class="pln"> your age</span><span class="pun">:</span><span class="pln">
forty two
</span><span class="typ">Please</span><span class="pln"> enter a number </span><span class="kwd">for</span><span class="pln"> your age</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> your age</span><span class="pun">:</span><span class="pln">
</span><span class="lit">42</span><span class="pln">
</span><span class="typ">Select</span><span class="pln"> a new password </span><span class="pun">(</span><span class="pln">letters </span><span class="kwd">and</span><span class="pln"> numbers only</span><span class="pun">):</span><span class="pln">
secr3t</span><span class="pun">!</span><span class="pln">
</span><span class="typ">Passwords</span><span class="pln"> can only have letters </span><span class="kwd">and</span><span class="pln"> numbers</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Select</span><span class="pln"> a new password </span><span class="pun">(</span><span class="pln">letters </span><span class="kwd">and</span><span class="pln"> numbers only</span><span class="pun">):</span><span class="pln">
secr3t</span></pre>

<p>
	تمكّنا من التحقق من صلاحية مدخلات المستخدم في المثال السابق باستخدام التابعين <code>isdecimal()‎</code> و isalnum()<code>‎</code>، ولم نقبل كتابة forty two بل قبلنا 42، ولم نقبل <code>secr3t!‎</code> بل قبلنا <code>secr3t</code>.
</p>

<h3 id="startswithendswith">
	التابعان startswith()‎ و endswith()‎
</h3>

<p>
	يعيد التابعان <code>startswith()‎</code> و <code>endswith()‎</code> القيمة <code>True</code> إن بدأت أو انتهت السلسلة النصية التي استدعت عليها (على التوالي) بالسلسلة النصية الممررة إلى التابع؛ وإلا فستعيد <code>False</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_59" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello, world!'</span><span class="pun">.</span><span class="pln">startswith</span><span class="pun">(</span><span class="str">'Hello'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello, world!'</span><span class="pun">.</span><span class="pln">endswith</span><span class="pun">(</span><span class="str">'world!'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'abc123'</span><span class="pun">.</span><span class="pln">startswith</span><span class="pun">(</span><span class="str">'abcdef'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'abc123'</span><span class="pun">.</span><span class="pln">endswith</span><span class="pun">(</span><span class="str">'12'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello, world!'</span><span class="pun">.</span><span class="pln">startswith</span><span class="pun">(</span><span class="str">'Hello, world!'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello, world!'</span><span class="pun">.</span><span class="pln">endswith</span><span class="pun">(</span><span class="str">'Hello, world!'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">True</span></pre>

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

<h3 id="joinsplit">
	التابعان join()‎ و split()‎
</h3>

<p>
	يفيد التابع join()<code>‎</code> حينما يكون لدينا قائمة فيها سلاسل نصية ونريد أن نجمعها كلها مع بعضها بعضًا في سلسلة نصية واحدة؛ ويستدعى التابع join()<code>‎</code> على سلسلة نصية، ويقبل معاملًا هو قائمة list فيها سلاسل نصية، ويعيد سلسلةً نصيةً تساوي دمج السلاسل النصية كلها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_61" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">', '</span><span class="pun">.</span><span class="pln">join</span><span class="pun">([</span><span class="str">'cats'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rats'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bats'</span><span class="pun">])</span><span class="pln">
</span><span class="str">'cats, rats, bats'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">' '</span><span class="pun">.</span><span class="pln">join</span><span class="pun">([</span><span class="str">'My'</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">'is'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Simon'</span><span class="pun">])</span><span class="pln">
</span><span class="str">'My name is Simon'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'ABC'</span><span class="pun">.</span><span class="pln">join</span><span class="pun">([</span><span class="str">'My'</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">'is'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Simon'</span><span class="pun">])</span><span class="pln">
</span><span class="str">'MyABCnameABCisABCSimon'</span></pre>

<p>
	لاحظ أن السلسلة النصية التي استدعينا عليها التابع <code>join()‎</code> أصبحت موجودة بين كل سلسلتين نصيتين في القائمة الممررة كوسيط. فمثلًا حين استدعاء join(['cats', 'rats', 'bats'])<code>‎</code> على السلسلة النصية <code>‎', '‎</code> فيكون الناتج هو ‎'cats, rats, bats'<code>‎</code>.
</p>

<p>
	تذكر أن التابع join()<code>‎</code> يستدعى على سلسلة نصية ونمرر إليه قائمة، وليس العكس.
</p>

<p>
	يفعل التابع <code>split()‎</code> عكس فعل التابع <code>join()‎</code> تمامًا: يستدعى على سلسلة نصية وتعيد قائمةً من السلاسل النصية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_63" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'My name is Simon'</span><span class="pun">.</span><span class="pln">split</span><span class="pun">()</span><span class="pln">
</span><span class="pun">[</span><span class="str">'My'</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">'is'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Simon'</span><span class="pun">]</span></pre>

<p>
	ستُقسَم السلسلة النصية 'My name is Simon' افتراضيًا عند كل محرف يمثل فراغًا (سواءً كان فراغًا عاديًا <code>' '</code> أو محرف جدولة tab أو سطرًا جديدًا newline)، ولن تضمن الفراغات في السلاسل النصية الموجودة في القائمة المعادة من استدعاء هذا التابع.
</p>

<p>
	يمكننا تمرير محرف الفصل إلى التابع <code>split()‎</code> لتحديد محرف آخر غير محارف الفراغات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_65" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'MyABCnameABCisABCSimon'</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">'ABC'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="str">'My'</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">'is'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Simon'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'My name is Simon'</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">'m'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="str">'My na'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'e is Si'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'on'</span><span class="pun">]</span></pre>

<p>
	من الشائع استدعاء التابع <code>split()‎</code> لتقسيم سلسلة نصية متعددة الأسطر في مكان وقوع محرف السطر الجديد:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_67" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="str">'''Dear Alice,
How have you been? I am fine.
There is a container in the fridge
that is labeled "Milk Experiment."

Please do not drink it.
Sincerely,
Bob'''</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">'\n'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="str">'Dear Alice,'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'How have you been? I am fine.'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'There is a container in the
fridge'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'that is labeled "Milk Experiment."'</span><span class="pun">,</span><span class="pln"> </span><span class="str">''</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Please do not drink it.'</span><span class="pun">,</span><span class="pln">
</span><span class="str">'Sincerely,'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Bob'</span><span class="pun">]</span></pre>

<p>
	يسمح لنا استدعاء التابع <code>split()‎</code> مع تمرير محرف السطر الجديد <code>'‎\n'</code> إلى تقسيم سلسلة نصية متعددة الأسطر إلى قائمة يمثل فيها كل عنصر سطرًا من الأسطر.
</p>

<h3 id="partition">
	تقسيم السلاسل النصية باستخدام التابع partition()‎
</h3>

<p>
	يمكن أن يقسم التابع <code>partition()‎</code> سلسلةً نصية إلى أقسام، ويعمل بتمرير سلسلة نصية إليه كفاصل، التي سيبحث عنها في السلسلة النصية التي استدعي عليها، ويعيد صفًا tuple فيه السلسلة النصية التي تسبق الفاصل، والفاصل، والسلسلة النصية التي تلي الفاصل:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_69" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello, world!'</span><span class="pun">.</span><span class="pln">partition</span><span class="pun">(</span><span class="str">'w'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">(</span><span class="str">'Hello, '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'w'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'orld!'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello, world!'</span><span class="pun">.</span><span class="pln">partition</span><span class="pun">(</span><span class="str">'world'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">(</span><span class="str">'Hello, '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'world'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'!'</span><span class="pun">)</span></pre>

<p>
	إذا احتوت السلسلة النصية التي تستدعي التابع <code>partition()‎</code> عليها على أكثر من تكرار للفاصل، فستقسم السلسلة النصية عند أول وقوع له فقط:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_71" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello, world!'</span><span class="pun">.</span><span class="pln">partition</span><span class="pun">(</span><span class="str">'o'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">(</span><span class="str">'Hell'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'o'</span><span class="pun">,</span><span class="pln"> </span><span class="str">', world!'</span><span class="pun">)</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_73" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello, world!'</span><span class="pun">.</span><span class="pln">partition</span><span class="pun">(</span><span class="str">'XYZ'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">(</span><span class="str">'Hello, world!'</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></pre>

<p>
	يمكننا استخدام نشر المتغيرات بالإسناد الجماعي لإسناد السلاسل النصية المعادة إلى ثلاثة متغيرات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_75" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> before</span><span class="pun">,</span><span class="pln"> sep</span><span class="pun">,</span><span class="pln"> after </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Hello, world!'</span><span class="pun">.</span><span class="pln">partition</span><span class="pun">(</span><span class="str">' '</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> before
</span><span class="str">'Hello,'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> after
</span><span class="str">'world!'</span></pre>

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

<h3 id="rjustljustcenter">
	محاذاة النصوص عبر rjust()‎ و ljust()‎ و center()‎
</h3>

<p>
	يعيد التابعان <code>rjust()‎</code> و <code>ljust()‎</code> سلسلةً نصية محاطة بفراغات افتراضيًا. يمثل أول وسيط يمرر إلى تلك التوابع قيمةً لعدد الفراغات المحيطة بالسلسلة النصية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_77" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello'</span><span class="pun">.</span><span class="pln">rjust</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span><span class="pln">
</span><span class="str">'     Hello'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello'</span><span class="pun">.</span><span class="pln">rjust</span><span class="pun">(</span><span class="lit">20</span><span class="pun">)</span><span class="pln">
</span><span class="str">'              Hello'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello, World'</span><span class="pun">.</span><span class="pln">rjust</span><span class="pun">(</span><span class="lit">20</span><span class="pun">)</span><span class="pln">
</span><span class="str">'         Hello, World'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello'</span><span class="pun">.</span><span class="pln">ljust</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span><span class="pln">
</span><span class="str">'Hello     '</span></pre>

<p>
	التابع <code>'Hello'.rjust(10)‎</code> يعني أننا نريد محاذاة السلسلة النصية <code>'Hello'</code> إلى اليمين ويكون طول السلسلة النصية الكاملة هو 10. ولما كانت <code>'Hello'</code> هي 5 محارف، فستضاف 5 فراغات على يسارها، مما يؤدي إلى إعادة سلسلة نصية طولها 10 محارف وتكون فيها محاذاة <code>'Hello'</code> على اليمين.
</p>

<p>
	وسيطٌ اختياري للتابعين rjust()<code>‎</code> و ljust()<code>‎</code> يحدد محرفًا للملء بخلاف الفراغ:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_79" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello'</span><span class="pun">.</span><span class="pln">rjust</span><span class="pun">(</span><span class="lit">20</span><span class="pun">,</span><span class="pln"> </span><span class="str">'*'</span><span class="pun">)</span><span class="pln">
</span><span class="str">'***************Hello'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello'</span><span class="pun">.</span><span class="pln">ljust</span><span class="pun">(</span><span class="lit">20</span><span class="pun">,</span><span class="pln"> </span><span class="str">'-'</span><span class="pun">)</span><span class="pln">
</span><span class="str">'Hello---------------'</span></pre>

<p>
	التابع <code>center()‎</code> يعمل مثل التابعين <code>ljust()‎</code> و rjust()<code>‎</code> لكنه يوسِّط النص بدلًا من محاذاته إلى اليسار أو اليمين:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_81" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello'</span><span class="pun">.</span><span class="pln">center</span><span class="pun">(</span><span class="lit">20</span><span class="pun">)</span><span class="pln">
</span><span class="str">'       Hello        '</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello'</span><span class="pun">.</span><span class="pln">center</span><span class="pun">(</span><span class="lit">20</span><span class="pun">,</span><span class="pln"> </span><span class="str">'='</span><span class="pun">)</span><span class="pln">
</span><span class="str">'=======Hello========'</span></pre>

<p>
	تفيد هذه التوابع حينما نريد طباعة جداول من البيانات ويكون لها تباعد صحيح. اكتب البرنامج الآتي واحفظه في الملف <code>picnicTable.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_83" style=""><span class="kwd">def</span><span class="pln"> printPicnic</span><span class="pun">(</span><span class="pln">itemsDict</span><span class="pun">,</span><span class="pln"> leftWidth</span><span class="pun">,</span><span class="pln"> rightWidth</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'PICNIC ITEMS'</span><span class="pun">.</span><span class="pln">center</span><span class="pun">(</span><span class="pln">leftWidth </span><span class="pun">+</span><span class="pln"> rightWidth</span><span class="pun">,</span><span class="pln"> </span><span class="str">'-'</span><span class="pun">))</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> k</span><span class="pun">,</span><span class="pln"> v </span><span class="kwd">in</span><span class="pln"> itemsDict</span><span class="pun">.</span><span class="pln">items</span><span class="pun">():</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">k</span><span class="pun">.</span><span class="pln">ljust</span><span class="pun">(</span><span class="pln">leftWidth</span><span class="pun">,</span><span class="pln"> </span><span class="str">'.'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">v</span><span class="pun">).</span><span class="pln">rjust</span><span class="pun">(</span><span class="pln">rightWidth</span><span class="pun">))</span><span class="pln">

picnicItems </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'sandwiches'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="str">'apples'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">12</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cups'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cookies'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">8000</span><span class="pun">}</span><span class="pln">
printPicnic</span><span class="pun">(</span><span class="pln">picnicItems</span><span class="pun">,</span><span class="pln"> </span><span class="lit">12</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln">
printPicnic</span><span class="pun">(</span><span class="pln">picnicItems</span><span class="pun">,</span><span class="pln"> </span><span class="lit">20</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">)</span></pre>

<p>
	عرفنا الدالة <code>printPicnic()‎</code> التي تأخذ قاموسًا كمعامل لها، واستخدمنا التوابع <code>center()‎</code> و <code>ljust()‎</code> و <code>rjust()‎</code> لطباعة المعلومات بصيغة جميلة تشبه الجدول.
</p>

<p>
	القاموس الذي سنمرره إلى الدالة <code>printPicnic()‎</code> هو <code>picnicItems</code>، ولدينا في القاموس <code>picnicItems 4</code> صندويشات و 12 تفاحة و 4 كاسات و 8,000 كعكة (نعم ثمانية آلاف!). نرغب بتنظيم هذه المعلومات في عمودين، ونضع اسم العنصر على اليسار والكمية على اليمين.
</p>

<p>
	لفعل ذلك نحتاج إلى أن نقرر كم سيكون عرض العمودين الأيسر والأيمن؛ لذا نحتاج إلى تمرير هاتين القيمتين مع القاموس إلى الدالة printPicnic()<code>‎</code> عبر المعاملين <code>leftWidth</code> لعرض العمود الأيسر من الجدول و <code>rightWidth</code> لعرض العمود الأيمن من الجدول.
</p>

<p>
	ستطبع الدالة <code>printPicnic()‎</code> عنوانًا متوسطًا فوق العنصر PICNIC ITEMS، ثم ستمر على عناصر القاموس وتطبع كل زوج من القيم في سطر وتحاذي المفتاح على اليسار وله حاشية متألفة من فواصل، والقيمة على اليمين ولها حاشية متألف من فراغات.
</p>

<p>
	بعد تعريف الدالة <code>printPicnic()‎</code> سنعرف القاموس <code>picnicItems</code> ونستدعي الدالة <code>printPicnic()‎</code> مرتين، مع تمرير عرض مختلف للعمودين الأيسر والأيمن؛ يكون فيها عرض العمود الأيسر 12 والأيمن 5 في المرة الأولى، ثم 20 و 6 في المرة الثانية.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_85" style=""><span class="pun">---</span><span class="pln">PICNIC ITEMS</span><span class="pun">--</span><span class="pln">
sandwiches</span><span class="pun">..</span><span class="pln">    </span><span class="lit">4</span><span class="pln">
apples</span><span class="pun">......</span><span class="pln">   </span><span class="lit">12</span><span class="pln">
cups</span><span class="pun">........</span><span class="pln">    </span><span class="lit">4</span><span class="pln">
cookies</span><span class="pun">.....</span><span class="pln"> </span><span class="lit">8000</span><span class="pln">
</span><span class="pun">-------</span><span class="pln">PICNIC ITEMS</span><span class="pun">-------</span><span class="pln">
sandwiches</span><span class="pun">..........</span><span class="pln">     </span><span class="lit">4</span><span class="pln">
apples</span><span class="pun">..............</span><span class="pln">    </span><span class="lit">12</span><span class="pln">
cups</span><span class="pun">................</span><span class="pln">     </span><span class="lit">4</span><span class="pln">
cookies</span><span class="pun">.............</span><span class="pln">  </span><span class="lit">8000</span></pre>

<p>
	رأينا كيف استفدنا من <code>rjust()‎</code> و ljust()<code>‎</code> و <code>center()‎</code> لطباعة سلاسل نصية منسقة تنسيقًا جميلًا، حتى لو لم نكن نعرف كم سيكون العدد الدقيق لمحارف السلسلة النصية التي سنطبعها.
</p>

<h3 id="striprstriplstrip">
	حذف الفراغات عبر strip()‎ و rstrip()‎ و lstrip()‎
</h3>

<p>
	نحتاج أحيانًا إلى حذف الفراغات البيضاء (التي هي محارف الفراغ العادي ومسافة الجدولة tab والسطر الجديد newline) من الطرف الأيسر أو الأيمن أو من كلا طرفي السلسلة النصية.
</p>

<p>
	سيعيد التابع <code>strip()‎</code> سلسلةً نصيةً جديدةً لا تحتوي على أي فراغات في بدايتها أو نهايتها، بينما يحذف التابعان <code>lstrip()‎</code> و <code>rstrip()‎</code> الفراغات البيضان من الطرف الأيسر أو الأيمن على التوالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_87" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="str">'    Hello, World    '</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">strip</span><span class="pun">()</span><span class="pln">
</span><span class="str">'Hello, World'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">lstrip</span><span class="pun">()</span><span class="pln">
</span><span class="str">'Hello, World    '</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">rstrip</span><span class="pun">()</span><span class="pln">
</span><span class="str">'    Hello, World'</span></pre>

<p>
	يمكننا تمرير وسيط اختياري يحتوي على المحارف التي نريد حذفها بدلًا من الفراغات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_89" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="str">'SpamSpamOliveSpamEggsSpamSpam'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">strip</span><span class="pun">(</span><span class="str">'ampS'</span><span class="pun">)</span><span class="pln">
</span><span class="str">'OliveSpamEggs'</span></pre>

<p>
	تمرير الوسيط <code>'ampS'</code> إلى التابع <code>strip()‎</code> سيؤدي إلى حذف جميع تكرارات المحارف a و m و p و S من بداية ونهاية السلسلة النصية <code>spam</code>. لاحظ أن ترتيب الأحرف في السلسلة النصية الممررة إلى التابع <code>strip()‎</code> لا يهم، فكتابة <code>strip('ampS')‎</code> تكافئ كتابة <code>strip('mapS')‎</code> أو <code>strip('Spam')‎</code>.
</p>

<h3 id="ordchr">
	القيم العددية للأحرف مع الدالتين ord()‎ و chr()‎
</h3>

<p>
	تخزن الحواسيب البيانات على هيئة بايتات، وهي سلاسل من البتات بنظام العد الثنائي، وهذا يعني أننا نحتاج إلى تحويل النصوص إلى أرقام لكي نستطيع تخزينها؛ ولهذا يكون لكل محرف character قيمة رقمية مرتبطة به تسمى Unicode code point. فمثلًا القيمة الرقمية 65 تمثل 'A'، والقيمة 52 تمثل '4'، والقيمة 33 تمثل '!'.
</p>

<p>
	يمكننا استخدام الدالة <code>ord()‎</code> للحصول على القيمة الرقمية لسلسلة نصية تحتوي محرفًا واحدًا، والدالة <code>chr()‎</code> للحصول على المحرف الذي وفرنا قيمته الرقمية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_91" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> ord</span><span class="pun">(</span><span class="str">'A'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">65</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> ord</span><span class="pun">(</span><span class="str">'4'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">52</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> ord</span><span class="pun">(</span><span class="str">'!'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">33</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> chr</span><span class="pun">(</span><span class="lit">65</span><span class="pun">)</span><span class="pln">
</span><span class="str">'A'</span></pre>

<p>
	تفيد هذه الدوال حينما نحتاج إلى ترتيب المحارف أو إجراء عمليات رياضية عليها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_93" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> ord</span><span class="pun">(</span><span class="str">'B'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">66</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> ord</span><span class="pun">(</span><span class="str">'A'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> ord</span><span class="pun">(</span><span class="str">'B'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> chr</span><span class="pun">(</span><span class="pln">ord</span><span class="pun">(</span><span class="str">'A'</span><span class="pun">))</span><span class="pln">
</span><span class="str">'A'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> chr</span><span class="pun">(</span><span class="pln">ord</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"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
</span><span class="str">'B'</span></pre>

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

<h2 id="pyperclip">
	نسخ ولصق السلاسل النصية باستخدام الوحدة pyperclip
</h2>

<p>
	تمتلك الوحدة <code>pyperclip</code> الدالتين copy()<code>‎</code> و <code>paste()‎</code> التي يمكنها إرسال واستقبال النص من حافظة <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> الذي تستعمله. إذ يسهل عليك إرسال ناتج برنامجك إلى الحافظة أن تلصقه في رسالةٍ بريدية أو في محرر النصوص أو غيره من البرمجيات.
</p>

<h3 id="mu">
	تشغيل سكربتات بايثون خارج محرر Mu
</h3>

<p>
	شغلنا كل سكربتات بايثون التي كتبناها حتى الآن باستخدام الصدفة التفاعلية ومحرر الشيفرات Mu؛ لكننا لسنا بحاجة إلى فتح محرر Mu في كل مرة نريد فيها تنفيذ سكربتات بايثون التي كتبناها. لحسن الحظ هنالك طرائق تسهل علينا تشغيل سكربتات بايثون، لكن هذه الطرائق تختلف من نظام ويندوز إلى MacOS ولينكس، وهي مشروحة في المقال الأول من هذه السلسلة، لذا أنصحك بالانتقال إلى المقال الأول لتعرف كيف تشغل سكربتات بايثون بسهولة على نظامك، وكيف تمرر خيارات <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%A7-%D9%87%D9%88-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%9F-r353/" rel="">سطر الأوامر</a> command line arguments إليها، لاحظ أنك لا تستطيع تمرير خيارات سطر الأوامر باستخدام محرر Mu.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_97" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> pyperclip
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> pyperclip</span><span class="pun">.</span><span class="pln">copy</span><span class="pun">(</span><span class="str">'Hello, world!'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> pyperclip</span><span class="pun">.</span><span class="pln">paste</span><span class="pun">()</span><span class="pln">
</span><span class="str">'Hello, world!'</span></pre>

<p>
	إذا غيّر أحد البرامج محتويات الحافظة فستعيدها الدالة paste()<code>‎</code>، فانسخ مثلًا عبارةً من المتصفح أو من محرر الشيفرات ثم استدعِ الدالة paste()<code>‎</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_99" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> pyperclip</span><span class="pun">.</span><span class="pln">paste</span><span class="pun">()</span><span class="pln">
</span><span class="str">'For example, if I copied this sentence to the clipboard and then called
paste(), it would look like this:'</span></pre>

<h2 id="-10">
	مشروع: حافظة فيها رسائل تلقائية
</h2>

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

<h3 id="1">
	الخطوة 1: تصميم البرنامج وبنى المعطيات
</h3>

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

<h4 id="-11">
	مشاريع الفصول
</h4>

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

<p>
	افتح نافذة محرر جديدة واحفظ البرنامج الآتي باسم <code>mclip.py</code>، ستحتاج إلى بدء البرنامج مع الرمز ‎#!<code>‎</code> (الذي يسمى shebang، راجع المقال الأول من هذه السلسلة)، ثم كتابة تعليق يشرح باختصار ما يفعله البرنامج.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_101" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># mclip.py - A multi-clipboard program.</span><span class="pln">

TEXT </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'agree'</span><span class="pun">:</span><span class="pln"> </span><span class="str">"""Yes, I agree. That sounds fine to me."""</span><span class="pun">,</span><span class="pln">
        </span><span class="str">'busy'</span><span class="pun">:</span><span class="pln"> </span><span class="str">"""Sorry, can we do this later this week or next week?"""</span><span class="pun">,</span><span class="pln">
        </span><span class="str">'upsell'</span><span class="pun">:</span><span class="pln"> </span><span class="str">"""Would you consider making this a monthly donation?"""</span><span class="pun">}</span></pre>

<h3 id="2">
	الخطوة 2: التعامل مع وسائط سطر الأوامر
</h3>

<p>
	تخزن الوسائط الممررة من سطر الأوامر command line arguments في المتغير <code>sys.argv</code> (راجع المقال الأول من هذه السلسلة لمزيدٍ من المعلومات حول استخدام وسائط سطر الأوامر في نظامك).
</p>

<p>
	يجب أن يكون أول عنصر في القائمة <code>sys.argv</code> هو سلسلة نصية تمثل اسم الملف <code>'mclip.py'</code> أما العنصر الثاني في القائمة فهو قيمة الوسيط الأول الممرر عبر سطر الأوامر.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_103" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># mclip.py - A multi-clipboard program.</span><span class="pln">

TEXT </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'agree'</span><span class="pun">:</span><span class="pln"> </span><span class="str">"""Yes, I agree. That sounds fine to me."""</span><span class="pun">,</span><span class="pln">
        </span><span class="str">'busy'</span><span class="pun">:</span><span class="pln"> </span><span class="str">"""Sorry, can we do this later this week or next week?"""</span><span class="pun">,</span><span class="pln">
        </span><span class="str">'upsell'</span><span class="pun">:</span><span class="pln"> </span><span class="str">"""Would you consider making this a monthly donation?"""</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> sys
</span><span class="kwd">if</span><span class="pln"> len</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="pln"> </span><span class="pun">&lt;</span><span class="pln"> </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="str">'Usage: python mclip.py [keyphrase] - copy phrase text'</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">

keyphrase </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="com"># أول وسيط في سطر الأوامر هو مفتاح العبارة التي نريد نسخها</span></pre>

<h3 id="3">
	الخطوة 3: نسخ العبارة الصحيحة
</h3>

<p>
	أصبح لدينا مفتاح العبارة مخزنًا في المتغير <code>keyphrase</code>، لذا ستحتاج إلى التحقق إن كان هذا المفتاح موجودًا في القاموس TEXT، فإن كان موجودًا فسننسخ العبارة المرتبطة بهذا المفتاح إلى الحافظة باستخدام الدالة <code>pyperclip.copy()‎</code>، ولمّا كنّا نستعمل الوحدة <code>pyperclip</code> فسنحتاج إلى استيرادها أيضًا.
</p>

<p>
	لاحظ أننا لسنا بحاجة إلى إنشاء المتغير <code>keyphrase</code>، إذ نستطيع استخدام <code>sys.argv[1]‎</code> في أي مكان استعملنا فيه <code>keyphrase</code> لكن وجود متغير باسم <code>keyphrase</code> سيسهل قراءة الشيفرة كثيرًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_105" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># mclip.py - A multi-clipboard program.</span><span class="pln">

TEXT </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'agree'</span><span class="pun">:</span><span class="pln"> </span><span class="str">"""Yes, I agree. That sounds fine to me."""</span><span class="pun">,</span><span class="pln">
        </span><span class="str">'busy'</span><span class="pun">:</span><span class="pln"> </span><span class="str">"""Sorry, can we do this later this week or next week?"""</span><span class="pun">,</span><span class="pln">
        </span><span class="str">'upsell'</span><span class="pun">:</span><span class="pln"> </span><span class="str">"""Would you consider making this a monthly donation?"""</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> sys</span><span class="pun">,</span><span class="pln"> pyperclip
</span><span class="kwd">if</span><span class="pln"> len</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="pln"> </span><span class="pun">&lt;</span><span class="pln"> </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="str">'Usage: py mclip.py [keyphrase] - copy phrase text'</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">

keyphrase </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="com"># first command line arg is the keyphrase</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> keyphrase </span><span class="kwd">in</span><span class="pln"> TEXT</span><span class="pun">:</span><span class="pln">
    pyperclip</span><span class="pun">.</span><span class="pln">copy</span><span class="pun">(</span><span class="pln">TEXT</span><span class="pun">[</span><span class="pln">keyphrase</span><span class="pun">])</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Text for '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> keyphrase </span><span class="pun">+</span><span class="pln"> </span><span class="str">' copied to clipboard.'</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="str">'There is no text for '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> keyphrase</span><span class="pun">)</span></pre>

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

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

<p>
	إذا كنت على نظام ويندوز فيمكنك إنشاء ملف دفعي batch file لتشغيل البرنامج باستخدام نافذة تشغيل البرامج Run (بالضغط على Win+R). أدخل ما يلي في محرر النصوص واحفظه باسم <code>mclip.bat</code> في مجلد <code>C:\Windows</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_107" style=""><span class="lit">@py</span><span class="pun">.</span><span class="pln">exe C</span><span class="pun">:</span><span class="pln">\path_to_file\mclip</span><span class="pun">.</span><span class="pln">py </span><span class="pun">%*</span><span class="pln">
</span><span class="lit">@pause</span></pre>

<p>
	يمكننا بعد إنشاء الملف الدفعي أن نشغل برنامجنا بالضغط على Win+R ثم كتابة mclip key_phrase.
</p>

<h2 id="-12">
	مشروع: إضافة قائمة منقطة إلى ويكيبيديا
</h2>

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

<p>
	يأخذ السكربت <code>bulletPointAdder.py</code> النص الموجود في الحافظة ويضيف نجمة وفراغًا إلى بداية كل سطر فيه، ثم يحفظ النص الناتج إلى الحافظة. فمثلًا إذا نسخت النص الآتي من صفحة ويكيبيديا المسماة «قائمة القوائم» List of Lists of Lists إلى الحافظة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_109" style=""><span class="typ">Lists</span><span class="pln"> of animals
</span><span class="typ">Lists</span><span class="pln"> of aquarium life
</span><span class="typ">Lists</span><span class="pln"> of biologists by author abbreviation
</span><span class="typ">Lists</span><span class="pln"> of cultivars</span></pre>

<p>
	ثم شغلت البرنامج <code>bulletPointAdder.py</code> فستصبح محتويات الحافظة كما يلي:
</p>

<pre class="ipsCode">* Lists of animals
* Lists of aquarium life
* Lists of biologists by author abbreviation
* Lists of cultivars
</pre>

<p>
	ونستطيع الآن لصق النص الناتج إلى ويكيبيديا كقائمة منقطة.
</p>

<h3 id="1-1">
	الخطوة 1: النسخ واللصق من وإلى الحافظة
</h3>

<p>
	نريد من برنامج <code>bulletPointAdder.py</code> أن يفعل ما يلي:
</p>

<ol>
	<li>
		يأخذ النص الموجود في الحافظة
	</li>
	<li>
		يجري عليه عمليات
	</li>
	<li>
		يحفظ الناتج في الحافظة
	</li>
</ol>

<p>
	الخطوة الثانية صعبة بعض الشيء، لكن الخطوات 1 و 3 سهلة جدًا: كل ما علينا فعله هو استدعاء الدالتين <code>pyperclip.copy()‎</code> و <code>pyperclip.paste()‎</code>. لننشِئ برنامجًا ينفذ الخطوات 1 و 3:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_111" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># bulletPointAdder.py - Adds Wikipedia bullet points to the start</span><span class="pln">
</span><span class="com"># of each line of text on the clipboard.</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> pyperclip
text </span><span class="pun">=</span><span class="pln"> pyperclip</span><span class="pun">.</span><span class="pln">paste</span><span class="pun">()</span><span class="pln">

</span><span class="com"># TODO: فصل الأسطر وإضافة رمز النجمة</span><span class="pln">

pyperclip</span><span class="pun">.</span><span class="pln">copy</span><span class="pun">(</span><span class="pln">text</span><span class="pun">)</span></pre>

<p>
	التعليق الذي يبدأ بالكلمة TODO هو تذكير لنا أن علينا إكمال هذا الجزء من البرنامج، لذا ستكون الخطوة القادمة هي برمجة هذا الجزء.
</p>

<h3 id="2-1">
	الخطوة 2: فصل الأسطر وإضافة النجمة
</h3>

<p>
	ناتج استدعاء pyperclip.paste()<code>‎</code> يعيد النص الموجود في الحافظة كسلسة نصية واحدة، إذ سيبدو مثال «قائمة القوائم» الذي نسخناه على الشكل الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_113" style=""><span class="str">'Lists of animals\nLists of aquarium life\nLists of biologists by author
abbreviation\nLists of cultivars'</span></pre>

<p>
	يوجد المحرف <code>‎\n</code> في السلسلة النصية السابقة لعرضها على عدة أسطر حين لصقها من الحافظة، لاحظ أن السلسلة النصية السابقة «متعددة» الأسطر لوجود محرف التهريب <code>‎\n</code>. ستحتاج إلى إضافة نجمة إلى بداية كل سطر من الأسطر السابقة.
</p>

<p>
	يمكنك أن تكتب شيفرة تبحث عن المحرف <code>‎\n</code> وتضيف نجمةً قبله، أو أن تستعمل التابع split()<code>‎</code> لإعادة قائمة من السلاسل النصية يمثل كل عنصر فيها سطرًا من السلسلة النصية الأصلية، وبعد ذلك تضيف النجمة قبل كل عنصر:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_115" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># bulletPointAdder.py - Adds Wikipedia bullet points to the start</span><span class="pln">
</span><span class="com"># of each line of text on the clipboard.</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> pyperclip
text </span><span class="pun">=</span><span class="pln"> pyperclip</span><span class="pun">.</span><span class="pln">paste</span><span class="pun">()</span><span class="pln">

</span><span class="com"># فصل الأسطر وإضافة النجمة</span><span class="pln">
lines </span><span class="pun">=</span><span class="pln"> text</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">'\n'</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="pln">len</span><span class="pun">(</span><span class="pln">lines</span><span class="pun">)):</span><span class="pln">    </span><span class="com"># المرور على جميع عناصر القائمة</span><span class="pln">
    lines</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">'* '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> lines</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="com"># إضافة نجمة وفراغ قبل كل عنصر</span><span class="pln">

pyperclip</span><span class="pun">.</span><span class="pln">copy</span><span class="pun">(</span><span class="pln">text</span><span class="pun">)</span></pre>

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

<h3 id="3-1">
	الخطوة 3: دمج الأسطر المعدلة
</h3>

<p>
	تحتوي القائمة <code>lines</code> على الأسطر المعدلة التي تبدأ بالنجمة، لكن الدالة pyperclip.copy()<code>‎</code> تتعامل مع السلاسل النصية وليس مع القوائم، لذا نحتاج إلى تحويل القائمة إلى سلسلة نصية، وذلك بجمع عناصر مع بعضها بعضًا عبر التابع <code>join()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_117" style=""><span class="com">#! python3</span><span class="pln">
</span><span class="com"># bulletPointAdder.py - Adds Wikipedia bullet points to the start</span><span class="pln">
</span><span class="com"># of each line of text on the clipboard.</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> pyperclip
text </span><span class="pun">=</span><span class="pln"> pyperclip</span><span class="pun">.</span><span class="pln">paste</span><span class="pun">()</span><span class="pln">

</span><span class="com"># فصل الأسطر وإضافة النجمة</span><span class="pln">
lines </span><span class="pun">=</span><span class="pln"> text</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">'\n'</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="pln">len</span><span class="pun">(</span><span class="pln">lines</span><span class="pun">)):</span><span class="pln">    </span><span class="com"># المرور على جميع عناصر القائمة</span><span class="pln">
    lines</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">'* '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> lines</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="com"># إضافة نجمة وفراغ قبل كل عنصر</span><span class="pln">

text </span><span class="pun">=</span><span class="pln"> </span><span class="str">'\n'</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">lines</span><span class="pun">)</span><span class="pln">
pyperclip</span><span class="pun">.</span><span class="pln">copy</span><span class="pun">(</span><span class="pln">text</span><span class="pun">)</span></pre>

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

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

<h2 id="-13">
	برنامج قصير: اللغة السرية " أين الحلقة السابقة؟ يحتاج المثال إلى إعادة صياغة كليًا"
</h2>

<p>
	هنالك لغة سرية يلعب الأطفال ويستعملونها اسمها Pig Latin، وهي تحريف للكلمات الإنكليزية بقواعد بسيطة. فلو بدأت الكلمة بحرف متحرك فتضاف الكلمة yay إلى نهايتها، وإذا بدأت الكلمة بحرف ساكن أو تركيب ساكن (مثل ch أو gr) فسينقل ذاك الساكن إلى نهاية البرنامج مع إلحاق ay.
</p>

<p>
	لنكتب برنامجًا للتحويل إلى اللغة السرية يطبع شيئًا يشبه المثال الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_119" style=""><span class="typ">Enter</span><span class="pln"> the </span><span class="typ">English</span><span class="pln"> message to translate into </span><span class="typ">Pig</span><span class="pln"> </span><span class="typ">Latin</span><span class="pun">:</span><span class="pln">
</span><span class="typ">My</span><span class="pln"> name </span><span class="kwd">is</span><span class="pln"> AL SWEIGART </span><span class="kwd">and</span><span class="pln"> I am </span><span class="lit">4</span><span class="pun">,</span><span class="lit">000</span><span class="pln"> years old</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Ymay</span><span class="pln"> amenay isyay ALYAY EIGARTSWAY andyay </span><span class="typ">Iyay</span><span class="pln"> amyay </span><span class="lit">4</span><span class="pun">,</span><span class="lit">000</span><span class="pln"> yearsyay oldyay</span><span class="pun">.</span></pre>

<p>
	يستعمل برنامجنا التوابع التي تعرفنا عليها في هذا المقال احفظ السكربت الآتي في ملف باسم <code>pigLat.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_121" style=""><span class="com"># English to Pig Latin</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Enter the English message to translate into Pig Latin:'</span><span class="pun">)</span><span class="pln">
message </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">

VOWELS </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="str">'a'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'e'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'i'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'o'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'u'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'y'</span><span class="pun">)</span><span class="pln">

pigLatin </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">for</span><span class="pln"> word </span><span class="kwd">in</span><span class="pln"> message</span><span class="pun">.</span><span class="pln">split</span><span class="pun">():</span><span class="pln">
    </span><span class="com"># فصل الكلمات التي لا تبدأ بأحرف</span><span class="pln">
    prefixNonLetters </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
    </span><span class="kwd">while</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">word</span><span class="pun">)</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="kwd">and</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> word</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">isalpha</span><span class="pun">():</span><span class="pln">
        prefixNonLetters </span><span class="pun">+=</span><span class="pln"> word</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
        word </span><span class="pun">=</span><span class="pln"> word</span><span class="pun">[</span><span class="lit">1</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">word</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">
        pigLatin</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">prefixNonLetters</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">continue</span><span class="pln">

    </span><span class="com"># فصل الكلمات التي لا تنتهي بحرف</span><span class="pln">
    suffixNonLetters </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
    </span><span class="kwd">while</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> word</span><span class="pun">[-</span><span class="lit">1</span><span class="pun">].</span><span class="pln">isalpha</span><span class="pun">():</span><span class="pln">
        suffixNonLetters </span><span class="pun">+=</span><span class="pln"> word</span><span class="pun">[-</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
        word </span><span class="pun">=</span><span class="pln"> word</span><span class="pun">[:-</span><span class="lit">1</span><span class="pun">]</span><span class="pln">

    </span><span class="com"># تذكر حالة الأحرف</span><span class="pln">
    wasUpper </span><span class="pun">=</span><span class="pln"> word</span><span class="pun">.</span><span class="pln">isupper</span><span class="pun">()</span><span class="pln">
    wasTitle </span><span class="pun">=</span><span class="pln"> word</span><span class="pun">.</span><span class="pln">istitle</span><span class="pun">()</span><span class="pln">

    word </span><span class="pun">=</span><span class="pln"> word</span><span class="pun">.</span><span class="pln">lower</span><span class="pun">()</span><span class="pln"> </span><span class="com"># تحويل الكلمة إلى الحالة الصغيرة لتحويلها</span><span class="pln">

    </span><span class="com"># فصل الأحرف الساكنة في بداية الكلمة</span><span class="pln">
    prefixConsonants </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
    </span><span class="kwd">while</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">word</span><span class="pun">)</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="kwd">and</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> word</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> VOWELS</span><span class="pun">:</span><span class="pln">
        prefixConsonants </span><span class="pun">+=</span><span class="pln"> word</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
        word </span><span class="pun">=</span><span class="pln"> word</span><span class="pun">[</span><span class="lit">1</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"> prefixConsonants </span><span class="pun">!=</span><span class="pln"> </span><span class="str">''</span><span class="pun">:</span><span class="pln">
        word </span><span class="pun">+=</span><span class="pln"> prefixConsonants </span><span class="pun">+</span><span class="pln"> </span><span class="str">'ay'</span><span class="pln">
    </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
        word </span><span class="pun">+=</span><span class="pln"> </span><span class="str">'yay'</span><span class="pln">

    </span><span class="com"># إعادة الكلمة إلى حالتها الأصلية</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> wasUpper</span><span class="pun">:</span><span class="pln">
        word </span><span class="pun">=</span><span class="pln"> word</span><span class="pun">.</span><span class="pln">upper</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> wasTitle</span><span class="pun">:</span><span class="pln">
        word </span><span class="pun">=</span><span class="pln"> word</span><span class="pun">.</span><span class="pln">title</span><span class="pun">()</span><span class="pln">

    </span><span class="com"># إضافة الرموز التي استخرجناها سابقًا</span><span class="pln">
    pigLatin</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">prefixNonLetters </span><span class="pun">+</span><span class="pln"> word </span><span class="pun">+</span><span class="pln"> suffixNonLetters</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="str">' '</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">pigLatin</span><span class="pun">))</span></pre>

<p>
	لنلقِ نظرةً على الشيفرة من بدايتها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_123" style=""><span class="com"># English to Pig Latin</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Enter the English message to translate into Pig Latin:'</span><span class="pun">)</span><span class="pln">
message </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">

VOWELS </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="str">'a'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'e'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'i'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'o'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'u'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'y'</span><span class="pun">)</span></pre>

<p>
	طلبنا في البداية من المستخدم أن يدخل نصًا إنكليزيًا لتحويله إلى اللغة السرية، وأنشأنا أيضًا ثابتًا يحتوي على الأحرف الصوتية في الإنكليزية (بالإضافة إلى الحرف y) في صف tuple من السلاسل النصية.
</p>

<p>
	أنشأنا بعد ذلك المتغير <code>pigLatin</code> لتخزين الكلمات بعد تحويلها إلى اللغة السرية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_125" style=""><span class="pln">pigLatin </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">for</span><span class="pln"> word </span><span class="kwd">in</span><span class="pln"> message</span><span class="pun">.</span><span class="pln">split</span><span class="pun">():</span><span class="pln">
    </span><span class="com"># فصل الكلمات التي لا تبدأ بأحرف</span><span class="pln">
    prefixNonLetters </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
    </span><span class="kwd">while</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">word</span><span class="pun">)</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="kwd">and</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> word</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">isalpha</span><span class="pun">():</span><span class="pln">
        prefixNonLetters </span><span class="pun">+=</span><span class="pln"> word</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
        word </span><span class="pun">=</span><span class="pln"> word</span><span class="pun">[</span><span class="lit">1</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">word</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">
        pigLatin</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">prefixNonLetters</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">continue</span></pre>

<p>
	نريد أن نعالج كل كلمة بمفردها، لذا استعملنا التابع message.split()<code>‎</code> للحصول على قائمة بالكلمات، فالسلسلة النصية ‎'My name is AL SWEIGART and I am 4,000 years old.'‎ مع التابع <code>split()‎</code> سيعيد الناتج.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_127" style=""><span class="pln"> </span><span class="pun">‎[</span><span class="str">'My'</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">'is'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'AL'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'SWEIGART'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'and'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'I'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'am'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'4,000'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'years'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'old.'</span><span class="pun">]‎.</span></pre>

<p>
	سنحتاج إلى الاحتفاظ بأي رموز في بداية ونهاية كل كلمة، فلو كانت لدينا الكلمة 'old.‎' فستحول إلى 'oldyay.‎' بدلًا من 'old.yay'. سنحتفظ بهذه الرموز في متغير باسم <code>prefixNonLetters</code>.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_129" style=""><span class="pln">    </span><span class="com"># فصل الكلمات التي لا تنتهي بحرف</span><span class="pln">
    suffixNonLetters </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
    </span><span class="kwd">while</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> word</span><span class="pun">[-</span><span class="lit">1</span><span class="pun">].</span><span class="pln">isalpha</span><span class="pun">():</span><span class="pln">
        suffixNonLetters </span><span class="pun">+=</span><span class="pln"> word</span><span class="pun">[-</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
        word </span><span class="pun">=</span><span class="pln"> word</span><span class="pun">[:-</span><span class="lit">1</span><span class="pun">]</span></pre>

<p>
	سنبدأ حلقة تكرار تستدعي التابع isalpha()<code>‎</code> على أول حرف من الكلمة لتتأكد إن كان علينا إزالة حرف من الكلمة وإضافته إلى نهاية السلسلة النصية <code>prefixNonLetters</code>، وإذا كانت الكلمة كلها تتألف من رموز أو أرقام مثل '4,000' فسنضيفها كما هي إلى القائمة pigLatin وننتقل إلى الكلمة التالية لنحولها إلى اللغة السرية. سنحتفظ بالرموز في نهاية السلسلة النصية word، وهذا يشبه الحلقة السابقة.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_131" style=""><span class="pln">    </span><span class="com"># تذكر حالة الأحرف</span><span class="pln">
    wasUpper </span><span class="pun">=</span><span class="pln"> word</span><span class="pun">.</span><span class="pln">isupper</span><span class="pun">()</span><span class="pln">
    wasTitle </span><span class="pun">=</span><span class="pln"> word</span><span class="pun">.</span><span class="pln">istitle</span><span class="pun">()</span><span class="pln">

    word </span><span class="pun">=</span><span class="pln"> word</span><span class="pun">.</span><span class="pln">lower</span><span class="pun">()</span><span class="pln"> </span><span class="com"># تحويل الكلمة إلى الحالة الصغيرة لتحويلها</span></pre>

<p>
	سنستخدم الكلمة المخزنة في المتغير <code>word</code> بحالتها الصغيرة حتى نهاية دورة <a href="https://wiki.hsoub.com/Python/for" rel="external">حلقة for</a>.
</p>

<p>
	لتحويل إحدى الكلمات مثل sweigart إلى eigart-sway فسنتحتاج إلى إزالة جميع الأحرف الساكنة من بداية الكلمة word:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_133" style=""><span class="pln">    </span><span class="com"># فصل الأحرف الساكنة في بداية الكلمة</span><span class="pln">
    prefixConsonants </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
    </span><span class="kwd">while</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">word</span><span class="pun">)</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="kwd">and</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> word</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> VOWELS</span><span class="pun">:</span><span class="pln">
        prefixConsonants </span><span class="pun">+=</span><span class="pln"> word</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
        word </span><span class="pun">=</span><span class="pln"> word</span><span class="pun">[</span><span class="lit">1</span><span class="pun">:]</span></pre>

<p>
	استخدمنا حلقة تكرار تشبه الحلقة التي أزالت الرموز من بداية الكلمة word، لكننا الآن نزيد الأحرف الساكنة ونخزنها في متغير باسم <code>prefixConsonants</code>.
</p>

<p>
	إذا لم يبقَ أي حرف ساكن في بداية الكلمة، فهذا يعني أنها أصبحت كلها في المتغير <code>prefixConsonants</code>، ويمكننا الآن جمع قيمة ذاك المتغير مع السلسلة النصية 'ay' في نهاية المتغير <code>word</code>. أما خلاف ذلك فهذا يعني أن <code>word</code> تبدأ بحرف صوتي، وسنحتاج إلى إضافة 'yay':
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_135" style=""><span class="pln">    </span><span class="com"># إضافة اللاحقة الخاصة باللغة السرية إلى نهاية الكلمة</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> prefixConsonants </span><span class="pun">!=</span><span class="pln"> </span><span class="str">''</span><span class="pun">:</span><span class="pln">
        word </span><span class="pun">+=</span><span class="pln"> prefixConsonants </span><span class="pun">+</span><span class="pln"> </span><span class="str">'ay'</span><span class="pln">
    </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
        word </span><span class="pun">+=</span><span class="pln"> </span><span class="str">'yay'</span></pre>

<p>
	تذكر أننا جعلنا الكلمة بحالة الأحرف الصغيرة word = word.lower()<code>‎</code>. أما إذا كانت القيمة <code>word</code> بحالة الأحرف الكبيرة أو نسق العناوين Title case فعلينا تحويلها إلى حالتها الأصلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_137" style=""><span class="pln">   </span><span class="com"># إعادة الكلمة إلى حالتها الأصلية</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> wasUpper</span><span class="pun">:</span><span class="pln">
        word </span><span class="pun">=</span><span class="pln"> word</span><span class="pun">.</span><span class="pln">upper</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> wasTitle</span><span class="pun">:</span><span class="pln">
        word </span><span class="pun">=</span><span class="pln"> word</span><span class="pun">.</span><span class="pln">title</span><span class="pun">()</span></pre>

<p>
	وفي نهاية دورة <a href="https://wiki.hsoub.com/Python/for" rel="external">حلقة for</a> سنضيف الكلمة مع أي رموز سابقة أو لاحقة إلى القائمة pigLatin:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_139" style=""><span class="pln">    </span><span class="com"># إضافة الرموز التي استخرجناها سابقًا</span><span class="pln">
    pigLatin</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">prefixNonLetters </span><span class="pun">+</span><span class="pln"> word </span><span class="pun">+</span><span class="pln"> suffixNonLetters</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="str">' '</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">pigLatin</span><span class="pun">))</span></pre>

<p>
	بعد نهاية حلقة التكرار فسنجمع عناصر القائمة pigLatin مع بعضها باستخدام التابع join()<code>‎</code>، وستمرر سلسلة نصية واحدة إلى الدالة print()<code>‎</code> لطباعة الجملة السرية.
</p>

<h2 id="-14">
	الخلاصة
</h2>

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

<p>
	صحيحٌ أن البرامج التي تكتبها الآن لا تبدو معقدة جدًا، فهي لا تحتوي على <a href="https://academy.hsoub.com/programming/python/%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-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-tkinter-r1501/" rel="">واجهات مستخدم رسومية</a> فيها صور ونصوص ملونة، فكل ما نستعمله هو الدالة <code>print()‎</code> لطباعة النصوص و <code>input()‎</code> لقبول مدخلات المستخدم؛ لكن يستطيع المستخدم إدخال مجموعة كبيرة من النصوص عبر نسخها إلى الحافظة، مما يفيد كثيرًا في معالجة كميات كبيرة من النصوص. وصحيحٌ أن هذه البرامج لا تملك واجهات رسومية جميلة لكنها تفعل الكثير بجهدٍ قليل.
</p>

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

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

<h2 id="-16">
	مشاريع تدريبية
</h2>

<p>
	لكي تتدرب، اكتب برامج لتنفيذ المهام الآتية.
</p>

<h3 id="-17">
	طابع جداول
</h3>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3960_142" style=""><span class="pln">tableData </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[[</span><span class="str">'apples'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'oranges'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cherries'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'banana'</span><span class="pun">],</span><span class="pln">
             </span><span class="pun">[</span><span class="str">'Alice'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Bob'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Carol'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'David'</span><span class="pun">],</span><span class="pln">
             </span><span class="pun">[</span><span class="str">'dogs'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cats'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'moose'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'goose'</span><span class="pun">]]</span></pre>

<p>
	يجب أن تطبع الدالة <code>printTable()‎</code> ما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3960_146">   apples Alice  dogs
  oranges   Bob  cats
 cherries Carol moose
   banana David goose</pre>

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

<p>
	يمكن أن تبدأ الدالة printTable()<code>‎</code> بالسطر <code>colWidths = [0] * len(tableData)‎</code> الذي سينشِئ قائمةً تحتوي على الرقم 0 يساوي عدد القوائم الداخلية الموجودة في القائمة tableData، وبالتالي ستخزن عرض أطول سلسلة نصية في <code>tableData[0]</code> في العنصر <code>colWidths[0]‎</code>، وعرض أطول سلسلة نصية في القائمة <code>tableData[1]</code> في العنصر <code>colWidths[1]</code> وهلم جرًا… ثم يمكنك الحصول على أكبر قيمة في القائمة colWidths لتعرف القيمة التي ستمررها كعرض إلى التابع <code>rjust()‎</code>.
</p>

<p>
	ترجمة -بتصرف- للفصل <a href="https://automatetheboringstuff.com/2e/chapter6/" rel="external nofollow">Manipulating Strings</a> من كتاب <a href="https://automatetheboringstuff.com/#toc" rel="external nofollow">Automate the Boring Stuff with Python</a>.
</p>

<h2 id="-18">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%82%D9%88%D8%A7%D9%85%D9%8A%D8%B3-%D9%88%D9%87%D9%8A%D9%83%D9%84%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2343/" rel="">القواميس وهيكلة البيانات في بايثون python</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-lists-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r2339/" rel="">القوائم Lists في لغة بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2322/" rel="">تهيئة بيئة العمل في بايثون Python</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2344</guid><pubDate>Thu, 13 Jun 2024 15:02:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x642;&#x648;&#x627;&#x645;&#x64A;&#x633; &#x648;&#x647;&#x64A;&#x643;&#x644;&#x629; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x641;&#x64A; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646; python</title><link>https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%82%D9%88%D8%A7%D9%85%D9%8A%D8%B3-%D9%88%D9%87%D9%8A%D9%83%D9%84%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2343/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_06/-Dictionaries----(1).png.cff954f78ab3af4fa619a6ad64c919d3.png" /></p>
<p>
	سنشرح في هذا المقال نوع البيانات المسمى بالقاموس dictionary، الذي يوفر طريقة مرنة للوصول إلى البيانات وتنظيمها، ثم سنتعلم كيفية كتابة لعبة إكس-أو عبر دمج ما تعلمناه في المقالات السابقة من هذه السلسلة مع القواميس.
</p>

<h2 id="dictionary">
	نوع البيانات dictionary
</h2>

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

<p>
	نسمي المفاتيح في القواميس بالمفاتيح keys، وكل مفتاح مرتبط بقيمة، ونسمي ذلك زوجًا من المفاتيح والقيم key-value pair. نكتب القواميس في <a href="https://academy.hsoub.com/python/" rel="">بايثون</a> بإحاطها بقوسين مجعدين أو معقوصين <code>{}</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_6" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> myCat </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'size'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'fat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'color'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'gray'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'disposition'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'loud'</span><span class="pun">}</span></pre>

<p>
	السطر السابق يسند قاموسًا إلى المتغير <code>myCat</code>، ومفاتيح هذا القاموس هي <code>'size'</code> و <code>'color'</code> و <code>'disposition'</code>، والقيم المرتبطة بتلك المفاتيح هي <code>'fat'</code> و <code>'gray'</code> و <code>'loud'</code> على التوالي وبالترتيب. يمكنك الوصول إلى هذه القيم عبر مفاتيحها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_8" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> myCat</span><span class="pun">[</span><span class="str">'size'</span><span class="pun">]</span><span class="pln">
</span><span class="str">'fat'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'My cat has '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> myCat</span><span class="pun">[</span><span class="str">'color'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">' fur.'</span><span class="pln">
</span><span class="str">'My cat has gray fur.'</span></pre>

<p>
	ما يزال بالإمكان استخدام الأعداد الصحيحة مفاتيحًا لقيم القواميس، لكن ليس من الضروري أن تبدأ من الصفر 0 ويمكنك استخدام أي رقم:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_10" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="lit">12345</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Luggage Combination'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">42</span><span class="pun">:</span><span class="pln"> </span><span class="str">'The Answer'</span><span class="pun">}</span></pre>

<h3 id="">
	مقارنة القواميس والقوائم
</h3>

<p>
	على خلاف القوائم، لا تكون القواميس مرتبةً، فأول عنصر في قائمة اسمها <code>spam</code> سيكون <code>spam[0]‎</code>، لكن لا يوجد «أول» عنصر في القاموس. سيكون ترتيب العناصر مهمًا في حال أردنا تحديد إن كانت قائمتان متساويتين، بينما لا يفرق ترتيب كتابة أزواج المفاتيح-القيم في القواميس:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_12" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cats'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dogs'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'moose'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> olive </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'dogs'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'moose'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cats'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">==</span><span class="pln"> olive
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggs </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'name'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Zophie'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'species'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'age'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'8'</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> steak </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'species'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'age'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'8'</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">'Zophie'</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggs </span><span class="pun">==</span><span class="pln"> steak
</span><span class="kwd">True</span></pre>

<p>
	ولأن القواميس غير مرتبة، فلا يمكن تقسيمها كما في القوائم.
</p>

<p>
	محاولة الوصول إلى مفتاح غير موجود في قاموس ما سيؤدي إلى حدوث الخطأ KeyError، وهي تشبه رسالة الخطأ IndexError في القوائم حين محاولة الوصول إلى قيمة خارج مجال فهارس القائمة. لاحظ رسالة الخطأ الآتية التي تظهر لعدم وجود المفتاح <code>'color'</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_14" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'name'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Zophie'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'age'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">7</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[</span><span class="str">'color'</span><span class="pun">]</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#1&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    spam</span><span class="pun">[</span><span class="str">'color'</span><span class="pun">]</span><span class="pln">
</span><span class="typ">KeyError</span><span class="pun">:</span><span class="pln"> </span><span class="str">'color'</span></pre>

<p>
	وصحيحٌ أن القواميس غير مرتبة، لكن إمكانية استخدام أي قيمة تريدها للمفاتيح يسمح لنا بترتيب البيانات بطرائق رائعة!
</p>

<p>
	لنقل أننا نريد كتابة برنامج يخزن معلومات حول أعياد ميلاد أصدقائك، يمكنك أن تكتب الشيفرة الآتية <code>birthdays.py</code> التي تستخدم القواميس وتجعل أسماء أصدقائك مفاتيحًا للقيم:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_16" style=""><span class="pun">➊</span><span class="pln"> birthdays </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'Alice'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Apr 1'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Bob'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Dec 12'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Carol'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Mar 4'</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">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Enter a name: (blank to quit)'</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="pln">
       </span><span class="kwd">if</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">break</span><span class="pln">

    </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"> birthdays</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">birthdays</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="str">' is the birthday of '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> name</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="str">'I do not have birthday information for '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> name</span><span class="pun">)</span><span class="pln">
           </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'What is their birthday?'</span><span class="pun">)</span><span class="pln">
           bday </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
        </span><span class="pun">➍</span><span class="pln"> birthdays</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"> bday
           </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Birthday database updated.'</span><span class="pun">)</span></pre>

<p>
	أنشأنا قاموسًا وخزناه في المتغير <code>birthdays</code> ➊، ثم تحققنا إن كان الاسم المدخل موجودًا في القاموس عبر الكلمة المحجوزة <code>in</code> ➋ كما كنا نفعل مع القوائم. إذا كان الاسم موجودًا في القاموس فيمكنك الوصول إلى القيمة المرتبطة به عبر استخدام الأقواس المربعة ➌، وإلّا فيمكنك إضافتها باستخدام صيغة الأقواس المربعة مع عامل الإسناد ➍:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_18" style=""><span class="typ">Enter</span><span class="pln"> a name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">blank to quit</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Alice</span><span class="pln">
</span><span class="typ">Apr</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> the birthday of </span><span class="typ">Alice</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> a name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">blank to quit</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Eve</span><span class="pln">
I </span><span class="kwd">do</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> have birthday information </span><span class="kwd">for</span><span class="pln"> </span><span class="typ">Eve</span><span class="pln">
</span><span class="typ">What</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> their birthday</span><span class="pun">?</span><span class="pln">
</span><span class="typ">Dec</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
</span><span class="typ">Birthday</span><span class="pln"> database updated</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> a name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">blank to quit</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Eve</span><span class="pln">
</span><span class="typ">Dec</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> the birthday of </span><span class="typ">Eve</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> a name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">blank to quit</span><span class="pun">)</span></pre>

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

<h3 id="37">
	القواميس المرتبة في بايثون 3.7
</h3>

<p>
	صحيح أن القواميس غير مرتبة ولا يوجد فيها عنصر «أول»، لكن القواميس في الإصدار 3.7 من بايثون وما يليه ستتذكر ترتيب أزواج القيم الموجودة فيها حين إنشاء متسلسل <code>sequence</code> منها. فمثلًا لاحظ أن ترتيب العناصر في القائمتين المنشأتين من القاموسين <code>eggs</code> و <code>steak</code> يطابق ترتيب إدخالها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_20" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggs </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'name'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Zophie'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'species'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'age'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'8'</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">eggs</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="str">'name'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'species'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'age'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> steak </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'species'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'age'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'8'</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">'Zophie'</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">steak</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="str">'species'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'age'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'name'</span><span class="pun">]</span></pre>

<p>
	ستبقى القواميس غير مرتبة، ولا يمكنك أن تصل إلى العناصر فيها عبر فهرس رقمي مثل <code>eggs[0]‎</code> أو <code>steak[2]‎</code>، لا يجدر بك الاعتماد على هذا السلوك لأن بايثون لا تتذكر ترتيب إدخال العناصر في الإصدارات القيمة منها، فلاحظ المثال الآتي الذي لا يطابق ترتيب عناصر القاموس الناتج النهائي الترتيبَ الذي أدخلتها به، ناتج التنفيذ الآتي على إصدار بايثون 3.5:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_22" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </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"> spam</span><span class="pun">[</span><span class="str">'first key'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'value'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[</span><span class="str">'second key'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'value'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[</span><span class="str">'third key'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'value'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">spam</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="str">'first key'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'third key'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'second key'</span><span class="pun">]</span></pre>

<h3 id="keysvaluesitems">
	التوابع keys()‎ و values()‎ و items()‎
</h3>

<p>
	هنالك ثلاثة توابع خاصة بالقواميس التي تعيد قيمًا شبيهة بالقوائم list-like من مفاتيح القواميس أو قيمها أو كلًا من المفاتيح والقيم معًا وهي التوابع <code>keys()‎</code> و <code>values()‎</code> و <code>items()‎</code> بالترتيب.
</p>

<p>
	القيم المعادة من هذه التوابع ليست قوائم حقيقيةً، فلا يمكننا تعديلها وليس لها التابع <code>append()‎</code>، لكن أنواع البيانات المعادة (وهي dict<em>keys و dict</em>values و dict_items بالترتيب) يمكن أن تستخدم في حلقات التكرار <code>for</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_24" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'color'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'red'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'age'</span><span class="pun">:</span><span class="pln"> </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="kwd">for</span><span class="pln"> v </span><span class="kwd">in</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">values</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">v</span><span class="pun">)</span><span class="pln">

red
</span><span class="lit">42</span></pre>

<p>
	ستمر حلقة for هنا على كل قيمة في القاموس <code>spam</code>، يمكن لحلقة <code>for</code> المرور على المفاتيح فقط، وعلى المفاتيح والقيم معًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_26" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> k </span><span class="kwd">in</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">keys</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">k</span><span class="pun">)</span><span class="pln">

color
age
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> i </span><span class="kwd">in</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">items</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">i</span><span class="pun">)</span><span class="pln">

</span><span class="pun">(</span><span class="str">'color'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'red'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">(</span><span class="str">'age'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">42</span><span class="pun">)</span></pre>

<p>
	حين استخدامنا للتوابع <code>keys()‎</code> و <code>values()‎</code> و <code>items()‎</code> فيمكن للحلقة <code>for</code> المرور على قيم المفاتيح أو قيم العناصر أو قيم أزواج المفتاح-القيمة على التوالي. لاحظ أن القيم المعادة من <code>items()‎</code> هي صفوف tuples تحتوي على المفتاح ثم قيمته.
</p>

<p>
	إذا أردتَ قائمةً حقيقية من ناتج أحد تلك التوابع، فيمكننا تمرير القيمة الشبيهة بالقوائم إلى الدالة <code>list()‎</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_28" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'color'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'red'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'age'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">42</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">()</span><span class="pln">
dict_keys</span><span class="pun">([</span><span class="str">'color'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'age'</span><span class="pun">])</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">spam</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">())</span><span class="pln">
</span><span class="pun">[</span><span class="str">'color'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'age'</span><span class="pun">]</span></pre>

<p>
	يأخذ السطر <code>list(spam.keys())‎</code> القيمة ذات النوع dict_keys المعادة من التابع <code>keys()‎</code> ويمررها إلى الدالة <code>list()‎</code>، والتي تعيد بدورها قائمةً فيها <code>['color', 'age']</code>.
</p>

<p>
	يمكنك استخدام الإسناد المتعدد مع حلقة <code>for</code> لإسناد المفتاح والقيمة إلى متغيرات منفصلة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_30" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'color'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'red'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'age'</span><span class="pun">:</span><span class="pln"> </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="kwd">for</span><span class="pln"> k</span><span class="pun">,</span><span class="pln"> v </span><span class="kwd">in</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">items</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="str">'Key: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> k </span><span class="pun">+</span><span class="pln"> </span><span class="str">' Value: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">v</span><span class="pun">))</span><span class="pln">

</span><span class="typ">Key</span><span class="pun">:</span><span class="pln"> age </span><span class="typ">Value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">42</span><span class="pln">
</span><span class="typ">Key</span><span class="pun">:</span><span class="pln"> color </span><span class="typ">Value</span><span class="pun">:</span><span class="pln"> red</span></pre>

<h3 id="-1">
	التحقق من وجود مفتاح أو قيمة في قاموس
</h3>

<p>
	نتذكر من <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-lists-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r2339/" rel="">المقال السابق</a> أن العاملين <code>in</code> و <code>not in</code> يمكن أن يستخدما للتحقق من وجود قيمة في قائمة. ويمكننا استخدام نفس العاملين للتحقق من وجود قيمة ما في مفتاح أو قيمة في قاموس:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_32" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'name'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Zophie'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'age'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">7</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'name'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Zophie'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">values</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'color'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'color'</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'color'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> spam
</span><span class="kwd">False</span></pre>

<p>
	لاحظ أن كتابة <code>‎'color' in spam</code> هي مطابقة لكتابة <code>‎'color' in spam.keys()‎</code>. فإذا أردت التحقق من وجود (أو عدم وجود) مفتاح ما في قاموس فاستعمل الكلمة المحجوزة <code>in</code> (أو <code>not in</code>) مع القاموس نفسه.
</p>

<h3 id="get">
	التابع get()‎
</h3>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_34" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> picnicItems </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'apples'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cups'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'I am bringing '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">picnicItems</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'cups'</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="str">' cups.'</span><span class="pln">
</span><span class="str">'I am bringing 2 cups.'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'I am bringing '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">picnicItems</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'eggs'</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="str">' eggs.'</span><span class="pln">
</span><span class="str">'I am bringing 0 eggs.'</span></pre>

<p>
	ولعدم وجود المفتاح <code>'eggs'</code> في القاموس picnicItems فستعاد القيمة 0 من التابع <code>get()‎</code>، وإن لم نستعمل التابع get()<code>‎</code> في المثال السابق فستظهر رسالة خطأ كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_36" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> picnicItems </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'apples'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cups'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'I am bringing '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">picnicItems</span><span class="pun">[</span><span class="str">'eggs'</span><span class="pun">])</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">' eggs.'</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#34&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="str">'I am bringing '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">picnicItems</span><span class="pun">[</span><span class="str">'eggs'</span><span class="pun">])</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">' eggs.'</span><span class="pln">
</span><span class="typ">KeyError</span><span class="pun">:</span><span class="pln"> </span><span class="str">'eggs'</span></pre>

<h3 id="setdefault">
	التابع setdefault()‎
</h3>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_38" style=""><span class="pln">spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'name'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Pooka'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'age'</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="str">'color'</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> spam</span><span class="pun">:</span><span class="pln">
    spam</span><span class="pun">[</span><span class="str">'color'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'black'</span></pre>

<p>
	يوفر التابع <code>setdefault()‎</code> طريقة أسهل لفعل ذلك بسطر برمجي وحيد، فأول وسيط يمرر إلى التابع هو المفتاح الذي سنتحقق من وجوده، والوسيط الثاني هو القيمة التي ستُضبَط إن لم يكن المفتاح موجودًا. إذا كان المفتاح موجودًا فسيعيد التابع <code>setdefault()‎</code> قيمة ذاك المفتاح:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_40" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'name'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Pooka'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'age'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">setdefault</span><span class="pun">(</span><span class="str">'color'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'black'</span><span class="pun">)</span><span class="pln">
</span><span class="str">'black'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="pun">{</span><span class="str">'color'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'black'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'age'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</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">'Pooka'</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">setdefault</span><span class="pun">(</span><span class="str">'color'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'white'</span><span class="pun">)</span><span class="pln">
</span><span class="str">'black'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="pun">{</span><span class="str">'color'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'black'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'age'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</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">'Pooka'</span><span class="pun">}</span></pre>

<p>
	حينما استدعينا التابع <code>setdefault()‎</code> أول مرة، فتغيرت قيمة القاموس <code>spam</code> إلى <code>‎{'color': 'black', 'age': 5, 'name': 'Pooka'}‎</code>، وسيعيد التابع <code>setdefault()‎</code> القيمة <code>'black'</code> لأنها القيمة المضبوطة للمفتاح <code>'color'</code> حاليًا.
</p>

<p>
	لكن حين استدعاء <code>spam.setdefault('color', 'white')‎</code> فإن القيمة لن تتغير إلى <code>'white'</code> لأن القاموس <code>spam</code> يحتوي على مفتاح باسم <code>'color'</code>.
</p>

<p>
	التابع <code>setdefault()‎</code> هو اختصار جميل للتأكد من وجود مفتاح معين وضبط قيمته. هذا مثال عن برنامج يعدّ عدد مرات وجود كل حرف في سلسلة نصية. احفظ المثال الآتي باسم <code>characterCount.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_42" style=""><span class="pln">message </span><span class="pun">=</span><span class="pln"> </span><span class="str">'It was a bright cold day in April, and the clocks were striking
thirteen.'</span><span class="pln">
count </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"> character </span><span class="kwd">in</span><span class="pln"> message</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">setdefault</span><span class="pun">(</span><span class="pln">character</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"> count</span><span class="pun">[</span><span class="pln">character</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">character</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="kwd">print</span><span class="pun">(</span><span class="pln">count</span><span class="pun">)</span><span class="pln">    </span></pre>

<p>
	سيمر البرنامج على كل محرف في السلسلة النصية المخزنة في المتغير <code>message</code>، ويعد كم مرة يظهر فيها كل محرف.
</p>

<p>
	استدعاء الدالة <code>setdefault()‎</code> ➊ سيضمن وجود المفتاح في القاموس count ويضبط قيمته الافتراضية إلى 0، وبالتالي لا يرمي البرنامج الخطأ KeyError حين تنفيذ التعبير البرمجي <code>count[character] = count[character] + 1</code> ➋. سيبدو الناتج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_44" style=""><span class="pun">{</span><span class="str">' '</span><span class="pun">:</span><span class="pln"> </span><span class="lit">13</span><span class="pun">,</span><span class="pln"> </span><span class="str">','</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">'.'</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">'A'</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">'I'</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">'a'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="str">'c'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="str">'b'</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">'e'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="str">'d'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="str">'g'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
</span><span class="str">'i'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="str">'h'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="str">'k'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="str">'l'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="str">'o'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="str">'n'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="str">'p'</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">'s'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="str">'r'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="str">'t'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="str">'w'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="str">'y'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">}</span></pre>

<p>
	سترى من الناتج السابق أن الحرف c الصغير مكرر 3 مرات، بينما الفراغ مكرر 13 مرة، والحرف A الكبير يظهر مرة واحدة. سيعمل البرنامج السابق على جميع السلاسل النصية بغض النظر عن محتويات المتغير <code>message</code> حتى لو كان يحتوي على مليون حرف!
</p>

<h2 id="-2">
	تجميل الطباعة
</h2>

<p>
	إذا استوردت الوحدة <code>pprint</code> في برامجك، فيمكنك الوصول إلى الدالتين pprint()<code>‎</code> و <code>pformat()‎</code> التي «تجمل طباعة» pretty print قيم القواميس، ستستفيد من هذه الدوال إن أردت عرض قيم القواميس عرضًا أجمل من طريقة عرض الدالة <code>print()‎</code>، لنعدل المثال السابق:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_47" style=""><span class="kwd">import</span><span class="pln"> pprint
message </span><span class="pun">=</span><span class="pln"> </span><span class="str">'It was a bright cold day in April, and the clocks were striking
thirteen.'</span><span class="pln">
count </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"> character </span><span class="kwd">in</span><span class="pln"> message</span><span class="pun">:</span><span class="pln">
    count</span><span class="pun">.</span><span class="pln">setdefault</span><span class="pun">(</span><span class="pln">character</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
    count</span><span class="pun">[</span><span class="pln">character</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">character</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">

pprint</span><span class="pun">.</span><span class="pln">pprint</span><span class="pun">(</span><span class="pln">count</span><span class="pun">)</span></pre>

<p>
	سيظهر لنا الناتج الجميل الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_49" style=""><span class="pun">{</span><span class="str">' '</span><span class="pun">:</span><span class="pln"> </span><span class="lit">13</span><span class="pun">,</span><span class="pln">
 </span><span class="str">','</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">'.'</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">'A'</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">'I'</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">snip</span><span class="pun">--</span><span class="pln">
 </span><span class="str">'t'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">6</span><span class="pun">,</span><span class="pln">
 </span><span class="str">'w'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
 </span><span class="str">'y'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">}</span></pre>

<p>
	سنستفيد فعليًا من الدالة <code>pprint.pprint()‎</code> عندما يحتوي القاموس على قوائم أو قواميس متشعبة داخله nested.
</p>

<p>
	إذا أردت الحصول على قيمة النص المجمّل بدلًا من طباعته على الشاشة مباشرةً، فاستدعِ الدالة <code>pprint.pformat()‎</code>. السطران الآتيان متكافئان تمامًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_51" style=""><span class="pln">pprint</span><span class="pun">.</span><span class="pln">pprint</span><span class="pun">(</span><span class="pln">someDictionaryValue</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">pprint</span><span class="pun">.</span><span class="pln">pformat</span><span class="pun">(</span><span class="pln">someDictionaryValue</span><span class="pun">))</span></pre>

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

<p>
	تمثل الفراغات في رقعة الشطرنج في التأشير الجبري Algebraic chess notation بإحداثيات تتألف من حرف ورقم كما في الشكل 5-1.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150958" href="https://academy.hsoub.com/uploads/monthly_2024_06/000006.jpg.e38719c9bc505455f9bfd5d2f3c6459c.jpg" rel=""><img alt="000006" class="ipsImage ipsImage_thumbnailed" data-fileid="150958" data-unique="dl7ylwlt5" src="https://academy.hsoub.com/uploads/monthly_2024_06/000006.jpg.e38719c9bc505455f9bfd5d2f3c6459c.jpg"> </a>
</p>

<p style="text-align: center;">
	الشكل 5-1: إحداثيات رقعة الشطرنج في التأشير الجبري
</p>

<p>
	تُعرّف قطع الشطرنج بالأحرف: K للملك king، و Q للملكة queen (يسميها البعض بالوزير)، و R للقلعة rook، و B للفيل bishop، و N للحصان knight. أما الجنود فلا رمز لهم.
</p>

<p>
	يكون وصف الحركات متألفًا من الحرف الذي يمثل القطعة، وإحداثيات الوجهة. وزوج من تلك الحركات يصف ما يحدث في دورٍ واحد (بفرض أن صاحب اللون الأبيض يبدأ أولًا)؛ فمثلًا التأشير 2‎. Nf3 Nc6 يعني أن الأبيض حرك الحصان إلى f3 والأسود حرك الحصان إلى c6 في الدور الثاني من اللعبة.
</p>

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

<p>
	تمتلك الحواسيب ذواكر رائعة، فيمكن أن يخزن الحاسوب مليارات السلاسل النصية من الشكل ‎'2. Nf3 Nc6'‎، وبهذا يمكن أن تلعب الحواسيب الشطرنج دون لوحة حقيقية؛ فما تفعله الحواسيب هو نمذجة البيانات لتمثيل رقعة الشطرنج، ويمكنك كتابة شيفرة تفعل ذلك بنفسك.
</p>

<p>
	هنا تلعب القوائم والقواميس دورها، فمثلًا القاموس ‎{'1h': 'bking', '6c': 'wqueen', '2g': 'bbishop', '5h': 'bqueen', '3e': 'wking'}<code>‎</code> يمثل الرقعة في الشكل 5-2:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150956" href="https://academy.hsoub.com/uploads/monthly_2024_06/000101.jpg.794680074d9114d77b01e1f9340ab1ca.jpg" rel=""><img alt="000101" class="ipsImage ipsImage_thumbnailed" data-fileid="150956" data-unique="tsggr6v74" src="https://academy.hsoub.com/uploads/monthly_2024_06/000101.jpg.794680074d9114d77b01e1f9340ab1ca.jpg"> </a>
</p>

<p style="text-align: center;">
	الشكل 5-2: رقعة شطرنج منمذجة وفق قيمة قاموس
</p>

<p>
	لكن لمثالنا القادمة سنستعمل لعبة أسهل وأبسط من الشطرنج وهي لعبة إكس-أو.
</p>

<h3 id="-3">
	لعبة إكس-أو
</h3>

<p>
	لعبة إكس-أو (تسمى بالإنكليزية tic-tac-toe) تشبه رمز # كبير فيه 9 خانات يمكن أن تكون قيمها X أو O أو أن تكون فارغة. لتمثيل هذه الرقعة بقاموس، فيجب أن نسند لكل خانة زوجًا من المفتاح-القيمة كما في الشكل 5-3.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150957" href="https://academy.hsoub.com/uploads/monthly_2024_06/000048.jpg.377ea41bdd607a4fd5213777539da337.jpg" rel=""><img alt="000048" class="ipsImage ipsImage_thumbnailed" data-fileid="150957" data-unique="m4kc54lea" src="https://academy.hsoub.com/uploads/monthly_2024_06/000048.jpg.377ea41bdd607a4fd5213777539da337.jpg"> </a>
</p>

<p style="text-align: center;">
	الشكل 5-3: خانات رقعة إكس-أو مع المفاتيح الموافقة لها
</p>

<p>
	يمكنك استخدام القيم النصية لتمثيل ما هو موجود في كل خانة في الرقعة: <code>'x'</code> أو <code>'o'</code> أو <code>' '</code> (فراغ)، وبالتالي نحتاج إلى تسع سلاسل نصية، يمكنك استخدام قاموس من القيم لهذا الأمر، فالقيمة النصية المرتبطة مع المفتاح <code>'top-R'</code> تمثل القيمة في الركن العلوي الأيمن، والسلسل النصية المرتبطة مع المفتاح <code>'low-L'</code> تمثل الركن السفلي الأيسر، والسلسلة النصية المرتبطة مع المفتاح <code>'mid-m'</code> تمثل المنتصف، وهلم جرًا للبقية.
</p>

<p>
	هذا القاموس هو بنية معطيات تمثل رقعة لعبة إكس-أو، ولنخزن هذا القاموس في متغير باسم <code>theBoard</code>، ولنحفظ الشيفرة الآتية في ملف باسم <code>ticTacToe.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_53" style=""><span class="pln">theBoard </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'top-L'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'top-M'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'top-R'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln">
            </span><span class="str">'mid-L'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'mid-M'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'mid-R'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln">
            </span><span class="str">'low-L'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'low-M'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'low-R'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">}</span></pre>

<p>
	بنية المعطيات المخزنة في المتغير <code>theBoard</code> تمثل رقعة إكس-أو الموضحة في الشكل 5-4.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150954" href="https://academy.hsoub.com/uploads/monthly_2024_06/000141.jpg.94e6b7390370ec4b828737e2746c300f.jpg" rel=""><img alt="000141" class="ipsImage ipsImage_thumbnailed" data-fileid="150954" data-unique="1lcr5ptai" src="https://academy.hsoub.com/uploads/monthly_2024_06/000141.jpg.94e6b7390370ec4b828737e2746c300f.jpg"> </a>
</p>

<p style="text-align: center;">
	الشكل 5-4: لوحة إكس-أو فارغة
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_55" style=""><span class="pln">theBoard </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'top-L'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'top-M'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'top-R'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln">
            </span><span class="str">'mid-L'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'mid-M'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'X'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'mid-R'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln">
            </span><span class="str">'low-L'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'low-M'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'low-R'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">}</span></pre>

<p>
	أصبحت بنية المعطيات <code>theBoard</code> تمثل الرقعة الموضحة في الشكل 5-5.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150955" href="https://academy.hsoub.com/uploads/monthly_2024_06/000084.jpg.9c1658717d05ddb81519e8f326f917fa.jpg" rel=""><img alt="000084" class="ipsImage ipsImage_thumbnailed" data-fileid="150955" data-unique="fps3qyjdf" src="https://academy.hsoub.com/uploads/monthly_2024_06/000084.jpg.9c1658717d05ddb81519e8f326f917fa.jpg"> </a>
</p>

<p style="text-align: center;">
	الشكل 5-5: الحركة الأولى
</p>

<p>
	وتكون رقعة ربح فيها اللاعب O بوضع الشكل O في الصف العلوي كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_57" style=""><span class="pln">theBoard </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'top-L'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'top-M'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'top-R'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln">
            </span><span class="str">'mid-L'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'X'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'mid-M'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'X'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'mid-R'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln">
            </span><span class="str">'low-L'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'low-M'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'low-R'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'X'</span><span class="pun">}</span></pre>

<p>
	وهي ممثلة في الشكل 5-6.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150953" href="https://academy.hsoub.com/uploads/monthly_2024_06/000020.jpg.f9ee5ba442be5de9a944a68ed4d51fcc.jpg" rel=""><img alt="000020" class="ipsImage ipsImage_thumbnailed" data-fileid="150953" data-unique="uhim82n18" src="https://academy.hsoub.com/uploads/monthly_2024_06/000020.jpg.f9ee5ba442be5de9a944a68ed4d51fcc.jpg"> </a>
</p>

<p style="text-align: center;">
	الشكل 5-6: ربح اللاعب O
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_59" style=""><span class="pln">theBoard </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'top-L'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'top-M'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'top-R'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln">
            </span><span class="str">'mid-L'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'mid-M'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'mid-R'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln">
            </span><span class="str">'low-L'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'low-M'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'low-R'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> printBoard</span><span class="pun">(</span><span class="pln">board</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">board</span><span class="pun">[</span><span class="str">'top-L'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'top-M'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'top-R'</span><span class="pun">])</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</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">board</span><span class="pun">[</span><span class="str">'mid-L'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'mid-M'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'mid-R'</span><span class="pun">])</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</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">board</span><span class="pun">[</span><span class="str">'low-L'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'low-M'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'low-R'</span><span class="pun">])</span><span class="pln">
printBoard</span><span class="pun">(</span><span class="pln">theBoard</span><span class="pun">)</span></pre>

<p>
	حينما تشغل هذا البرنامج فستطبع رقعة إكس-أو فارغة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_61" style=""><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>

<p>
	يمكن أن تتوالى الدالة <code>printBoard()‎</code> أي بنية معطيات تمثل رقعة إكس-أو تمررها إليها، جرب تغيير الشيفرة إلى ما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_63" style=""><span class="pln">theBoard </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'top-L'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'top-M'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'top-R'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'mid-L'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'X'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'mid-M'</span><span class="pun">:</span><span class="pln">
</span><span class="str">'X'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'mid-R'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'low-L'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'low-M'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'low-R'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'X'</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> printBoard</span><span class="pun">(</span><span class="pln">board</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">board</span><span class="pun">[</span><span class="str">'top-L'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'top-M'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'top-R'</span><span class="pun">])</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</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">board</span><span class="pun">[</span><span class="str">'mid-L'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'mid-M'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'mid-R'</span><span class="pun">])</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</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">board</span><span class="pun">[</span><span class="str">'low-L'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'low-M'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'low-R'</span><span class="pun">])</span><span class="pln">
printBoard</span><span class="pun">(</span><span class="pln">theBoard</span><span class="pun">)</span></pre>

<p>
	ستعرض الرقعة الآتية على الشاشة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_65" style=""><span class="pln">O</span><span class="pun">|</span><span class="pln">O</span><span class="pun">|</span><span class="pln">O
</span><span class="pun">-+-+-</span><span class="pln">
X</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></pre>

<p>
	ولأنك أنشأت بنية معطيات تمثل لوحة إكس-أو وكتبت الشيفرة في <code>printBoard()‎</code> التي تفسر بنية المعطيات وتظهر الرقعة، فأنت كتبت برنامجًا «ينمذج» models رقعة إكس-أو. كان بإمكانك تنظيم البيانات في بنية المعطيات بطريقة مختلفة، فمثلًا يمكنك استخدام المفتاح <code>'TOP-LEFT'</code> بدلًا من <code>'top-L'</code>، لكن طالما كانت شيفرتك تعمل مع بنية المعطيات التي لديك، فأنت كتبت عملية النمذجة بشكل صحيح.
</p>

<p>
	فمثلًا تتوقع الدالة <code>printBoard()‎</code> أن بنية المعطيات التي تمثل الرقعة هي قاموس فيه مفاتيح لجميع الخانات التسع، لكن إن كان في قاموسك مفتاحٌ ناقص وليكن <code>'mid-L'</code> فلن يعمل برنامجك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_67" style=""><span class="pln">O</span><span class="pun">|</span><span class="pln">O</span><span class="pun">|</span><span class="pln">O
</span><span class="pun">-+-+-</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"ticTacToe.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    printBoard</span><span class="pun">(</span><span class="pln">theBoard</span><span class="pun">)</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"ticTacToe.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> printBoard
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">board</span><span class="pun">[</span><span class="str">'mid-L'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'mid-M'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'mid-R'</span><span class="pun">])</span><span class="pln">
</span><span class="typ">KeyError</span><span class="pun">:</span><span class="pln"> </span><span class="str">'mid-L'</span></pre>

<p>
	لنضف الآن الشيفرة التي تسمح للاعبين بإدخال حركاتهم. لنعدل برنامجنا ليبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_69" style=""><span class="pln">theBoard </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'top-L'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'top-M'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'top-R'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'mid-L'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'mid-M'</span><span class="pun">:</span><span class="pln">
</span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'mid-R'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'low-L'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'low-M'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'low-R'</span><span class="pun">:</span><span class="pln"> </span><span class="str">' '</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> printBoard</span><span class="pun">(</span><span class="pln">board</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">board</span><span class="pun">[</span><span class="str">'top-L'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'top-M'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'top-R'</span><span class="pun">])</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</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">board</span><span class="pun">[</span><span class="str">'mid-L'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'mid-M'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'mid-R'</span><span class="pun">])</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</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">board</span><span class="pun">[</span><span class="str">'low-L'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'low-M'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'|'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> board</span><span class="pun">[</span><span class="str">'low-R'</span><span class="pun">])</span><span class="pln">
turn </span><span class="pun">=</span><span class="pln"> </span><span class="str">'X'</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">9</span><span class="pun">):</span><span class="pln">
  </span><span class="pun">➊</span><span class="pln"> printBoard</span><span class="pun">(</span><span class="pln">theBoard</span><span class="pun">)</span><span class="pln">
     </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Turn for '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> turn </span><span class="pun">+</span><span class="pln"> </span><span class="str">'. Move on which space?'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">➋</span><span class="pln"> move </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">➌</span><span class="pln"> theBoard</span><span class="pun">[</span><span class="pln">move</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> turn
  </span><span class="pun">➍</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> turn </span><span class="pun">==</span><span class="pln"> </span><span class="str">'X'</span><span class="pun">:</span><span class="pln">
         turn </span><span class="pun">=</span><span class="pln"> </span><span class="str">'O'</span><span class="pln">
     </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
         turn </span><span class="pun">=</span><span class="pln"> </span><span class="str">'X'</span><span class="pln">
 printBoard</span><span class="pun">(</span><span class="pln">theBoard</span><span class="pun">)</span></pre>

<p>
	الشيفرة الجديدة تطبع اللوحة في بداية كل دور ➊ ثم تطلب المدخلات من اللاعب الحالي ➋ ثم تحدث الرقعة وفقًا لذلك ➌ ثم تبدل اللاعب الحالي ➍ قبل الانتقال إلى الدور القادم.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_71" style=""><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="typ">Turn</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> X</span><span class="pun">.</span><span class="pln"> </span><span class="typ">Move</span><span class="pln"> on which space</span><span class="pun">?</span><span class="pln">
mid</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="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"> </span><span class="pun">|</span><span class="pln">

</span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">

O</span><span class="pun">|</span><span class="pln">O</span><span class="pun">|</span><span class="pln">X
</span><span class="pun">-+-+-</span><span class="pln">
X</span><span class="pun">|</span><span class="pln">X</span><span class="pun">|</span><span class="pln">O
</span><span class="pun">-+-+-</span><span class="pln">
O</span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln">X
</span><span class="typ">Turn</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> X</span><span class="pun">.</span><span class="pln"> </span><span class="typ">Move</span><span class="pln"> on which space</span><span class="pun">?</span><span class="pln">
low</span><span class="pun">-</span><span class="pln">M
O</span><span class="pun">|</span><span class="pln">O</span><span class="pun">|</span><span class="pln">X
</span><span class="pun">-+-+-</span><span class="pln">
X</span><span class="pun">|</span><span class="pln">X</span><span class="pun">|</span><span class="pln">O
</span><span class="pun">-+-+-</span><span class="pln">
O</span><span class="pun">|</span><span class="pln">X</span><span class="pun">|</span><span class="pln">X</span></pre>

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

<h2 id="-4">
	القواميس والقوائم المتشعبة
</h2>

<p>
	نمذجة لوحة إكس-أو هو أمر سهل: تحتاج اللوحة إلى قاموس فيه 9 مفاتيح تمثل خاناتها. لكن إن أردت نموذج أمور أكثر تعقيدًا فستجد أنك تحتاج إلى القواميس والقوائم التي تحتوي على قواميس وقوائم أخرى داخلها.
</p>

<p>
	تناسب القوائم تخزين سلسلة مرتبة من القيم، بينما تفيد القواميس بتخزين قواميس التي ترتبط فيها المفاتيح مع القيم.
</p>

<p>
	هذا مثال يستعمل قاموسًا يحتوي على قواميس داخله فيها الأغراض التي أتى بها الضيوف إلى الرحلة. يمكن أن تقرأ الدالة <code>totalBrought()‎</code> بنية المعطيات وتحسب العدد الكلي للعناصر المجلوبة من كل الضيوف:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_73" style=""><span class="pln">allGuests </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'Alice'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="str">'apples'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="str">'pretzels'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">12</span><span class="pun">},</span><span class="pln">
             </span><span class="str">'Bob'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="str">'steak sandwiches'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="str">'apples'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">},</span><span class="pln">
             </span><span class="str">'Carol'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="str">'cups'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="str">'apple pies'</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">def</span><span class="pln"> totalBrought</span><span class="pun">(</span><span class="pln">guests</span><span class="pun">,</span><span class="pln"> item</span><span class="pun">):</span><span class="pln">
    numBrought </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
  </span><span class="pun">➊</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> k</span><span class="pun">,</span><span class="pln"> v </span><span class="kwd">in</span><span class="pln"> guests</span><span class="pun">.</span><span class="pln">items</span><span class="pun">():</span><span class="pln">
      </span><span class="pun">➋</span><span class="pln"> numBrought </span><span class="pun">=</span><span class="pln"> numBrought </span><span class="pun">+</span><span class="pln"> v</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">item</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"> numBrought

</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Number of things being brought:'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">' - Apples         '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">totalBrought</span><span class="pun">(</span><span class="pln">allGuests</span><span class="pun">,</span><span class="pln"> </span><span class="str">'apples'</span><span class="pun">)))</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">' - Cups           '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">totalBrought</span><span class="pun">(</span><span class="pln">allGuests</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cups'</span><span class="pun">)))</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">' - Cakes          '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">totalBrought</span><span class="pun">(</span><span class="pln">allGuests</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cakes'</span><span class="pun">)))</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">' - Steak Sandwiches '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">totalBrought</span><span class="pun">(</span><span class="pln">allGuests</span><span class="pun">,</span><span class="pln"> </span><span class="str">'steak sandwiches'</span><span class="pun">)))</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">' - Apple Pies     '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">totalBrought</span><span class="pun">(</span><span class="pln">allGuests</span><span class="pun">,</span><span class="pln"> </span><span class="str">'apple pies'</span><span class="pun">)))</span></pre>

<p>
	داخل الدالة <code>totalBrought()‎</code> هنالك <a href="https://wiki.hsoub.com/Python#for" rel="external">حلقة for</a> تدور على أزواج مفتاح-قيمة في المتغير <code>guests</code> ➊، وسنسند داخل الحلقة اسم كل ضيف إلى المتغير <code>k</code>، وسنسند القاموس الذي يحتوي على قائمة الأغراض التي سيجلبها معه إلى الرحلة إلى المتغير v. إذا كان أحد المعامل item موجودة في القاموس، فستضاف قيمته (كمية الأغراض المجلوبة) إلى المتغير <code>numBrought</code> ➋، لكن إذا لم يكن المفتاح موجودًا فيسعيد التابع get()<code>‎</code> القيمة 0 لإضافتها إلى <code>numBrought</code>.
</p>

<p>
	سيكون ناتج تنفيذ البرنامج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_75" style=""><span class="pln"> </span><span class="typ">Number</span><span class="pln"> of things being brought</span><span class="pun">:</span><span class="pln">
 </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Apples</span><span class="pln"> </span><span class="lit">7</span><span class="pln">
 </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Cups</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
 </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Cakes</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
 </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Steak</span><span class="pln"> </span><span class="typ">Sandwiches</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
 </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Apple</span><span class="pln"> </span><span class="typ">Pies</span><span class="pln"> </span><span class="lit">1</span></pre>

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

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

<p>
	حينما تبدأ البرمجة فلا تقلق أن تنمذج البيانات بالطريقة «الصحيحة»، فكلما ازدادت خبرتك أصبحت تخطر ببالك طرائق أكثر فاعلية وكفاءة للنمذجة، لكن أهم ما في الأمر أن تعمل بنية المعطيات مع احتياجات برنامجك.
</p>

<h2 id="-5">
	الخلاصة
</h2>

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

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

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

<h2 id="-7">
	مشاريع تدريبية
</h2>

<p>
	لكي تتدرب، اكتب برامج لتنفيذ المهام الآتية.
</p>

<h3 id="-8">
	مدقق لقواميس الشطرنج
</h3>

<p>
	استعملنا في هذا المقال قيمةً مثل <code>‎{'1h': 'bking', '6c': 'wqueen', '2g': 'bbishop', '5h': 'bqueen', '3e': 'wking'}‎</code> لتمثيل رقعة الشطرنج. اكتب دالةً باسم <code>isValidChessBoard()‎</code> التي تقبل وسيطًا هو قاموس وتعيد القيمة <code>True</code> أو <code>False</code> اعتمادًا إن كان القاموس صالحًا لتمثيل رقعة الشطرنج.
</p>

<p>
	تحتوي الرقعة السليمة على ملك أسود واحد وملك أبيض واحد. ويمكن لأيٍ من اللاعبين امتلاك 16 قطعة كحد أقصى، و 8 جنود كحد أقصى، ويجب أن تكون جميع القطع في المجال بين 1a و 8h، أي لا يمكن أن تكون القطعة في المكان 9z. يجب أن تبدأ أسماء القطع بحرف w أو b لتمثيل اللونين الأبيض أو الأسود، متبوعًا بإحدى الكلمات pawn أو knight أو bishop أو rook أو queen أو king.
</p>

<h3 id="-9">
	قائمة الأدوات في لعبة
</h3>

<p>
	نحن نعمل على لعبة فيها قائمة أدوات يمكن أن يمتلكها اللاعب، والتي سننمذجها باستخدام بنية معطيات تتألف من قاموس تكون فيه مفاتيحه هي <a href="https://wiki.hsoub.com/Python/str" rel="external">سلاسل نصية</a> تصف القيمة الموجودة في قائمة الأدوات، وقيمتها هي عدد نصي يمثل عدد الأدوات التي يمتلكها اللاعب مثلًا القاموس <code>‎</code>{'rope': 1, 'torch': 6, 'gold coin': 42, 'dagger': 1, 'arrow': 12}‎ تعني أن اللاعب يملك حبلًا واحدًا، و 6 شعلات، و 42 قطعة ذهبية …إلخ.
</p>

<p>
	اكتب دالةً باسم displayInventory()<code>‎</code> التي تأخذ أي قاموس يمثل قائمة أدوات ويعرضه بالشكل:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_79" style=""><span class="typ">Inventory</span><span class="pun">:</span><span class="pln">
</span><span class="lit">12</span><span class="pln"> arrow
</span><span class="lit">42</span><span class="pln"> gold coin
</span><span class="lit">1</span><span class="pln"> rope
</span><span class="lit">6</span><span class="pln"> torch
</span><span class="lit">1</span><span class="pln"> dagger
</span><span class="typ">Total</span><span class="pln"> number of items</span><span class="pun">:</span><span class="pln"> </span><span class="lit">62</span></pre>

<p>
	تلميح: يمكنك استخدام حلقة <code>for</code> للمرور على جميع المفاتيح في القاموس:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_81" style=""><span class="com"># inventory.py</span><span class="pln">
stuff </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'rope'</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">'torch'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="str">'gold coin'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">42</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dagger'</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">'arrow'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">12</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> displayInventory</span><span class="pun">(</span><span class="pln">inventory</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">"Inventory:"</span><span class="pun">)</span><span class="pln">
    item_total </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> k</span><span class="pun">,</span><span class="pln"> v </span><span class="kwd">in</span><span class="pln"> inventory</span><span class="pun">.</span><span class="pln">items</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="str">"Total number of items: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">item_total</span><span class="pun">))</span><span class="pln">

displayInventory</span><span class="pun">(</span><span class="pln">stuff</span><span class="pun">)</span></pre>

<h3 id="-10">
	دالة تحويل قائمة إلى قاموس في لعبة
</h3>

<p>
	لنفترض أن لاعبنا في اللعبة السابقة قد حصل على غنيمة ممثلة في القائمة الآتية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_83" style=""><span class="pln">playerLoot </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'gold coin'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dagger'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'gold coin'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'gold coin'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'ruby'</span><span class="pun">]</span></pre>

<p>
	اكتب دالةً باسم <code>addToInventory(inventory, addedItems)‎</code> حيث أن المعامل <code>inventory</code> هو قاموس يمثل قائمة أدوات اللاعب (كما في المثال السابق) والمعامل <code>addedItems</code> يشبه المتغير <code>playerLoot</code>.
</p>

<p>
	يجب أن تعيد الدالة <code>addToInventory()‎</code> قاموسًا يمثل قائمة الأدوات المحدثة.
</p>

<p>
	لاحظ أن القائمة الموجودة في <code>addedItems</code> قد تحتوي على عدة نسخ من نفس الأداة. يفترض أن تكون شيفرتك شبيهة بما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_85" style=""><span class="kwd">def</span><span class="pln"> addToInventory</span><span class="pun">(</span><span class="pln">inventory</span><span class="pun">,</span><span class="pln"> addedItems</span><span class="pun">):</span><span class="pln">
    </span><span class="com"># اكتب الدالة هنا</span><span class="pln">

inv </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'gold coin'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">42</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rope'</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">}</span><span class="pln">
dragonLoot </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'gold coin'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dagger'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'gold coin'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'gold coin'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'ruby'</span><span class="pun">]</span><span class="pln">
inv </span><span class="pun">=</span><span class="pln"> addToInventory</span><span class="pun">(</span><span class="pln">inv</span><span class="pun">,</span><span class="pln"> dragonLoot</span><span class="pun">)</span><span class="pln">
displayInventory</span><span class="pun">(</span><span class="pln">inv</span><span class="pun">)</span></pre>

<p>
	يجب أن يظهر البرنامج السابق (مع الدالة <code>displayInventory()‎</code> من المثال السابق) الناتج الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1086_87" style=""><span class="typ">Inventory</span><span class="pun">:</span><span class="pln">
</span><span class="lit">45</span><span class="pln"> gold coin
</span><span class="lit">1</span><span class="pln"> rope
</span><span class="lit">1</span><span class="pln"> ruby
</span><span class="lit">1</span><span class="pln"> dagger

</span><span class="typ">Total</span><span class="pln"> number of items</span><span class="pun">:</span><span class="pln"> </span><span class="lit">48</span></pre>

<p>
	ترجمة -بتصرف- للفصل <a href="https://automatetheboringstuff.com/2e/chapter5/" rel="external nofollow">Dictionaries And Structuring DATA</a> من كتاب <a href="https://automatetheboringstuff.com/#toc" rel="external nofollow">Automate the Boring Stuff with Python</a>.
</p>

<h2 id="-11">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-lists-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r2339/" rel="">القوائم Lists في لغة بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/artificial-intelligence/%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-%D9%88%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1872/" rel="">أنواع البيانات والعمليات الأساسية في لغة بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/python/" rel="">تعلم لغة بايثون</a>
	</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>
</ul>
]]></description><guid isPermaLink="false">2343</guid><pubDate>Sun, 09 Jun 2024 15:03:01 +0000</pubDate></item><item><title>&#x627;&#x644;&#x642;&#x648;&#x627;&#x626;&#x645; Lists &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646;</title><link>https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-lists-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r2339/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_06/-Lists--.png.eabad0ba7e7d8848816264470ba41ae5.png" /></p>
<p>
	قبل أن تبدأ بكتابة البرامج عبر بايثون، هنا موضوع مهم يجب أن تعرفه إلى جانب ما تعرفت عليه بالمقالات السابقة <a href="https://academy.hsoub.com/search/?tags=%D8%A3%D8%AA%D9%85%D8%AA%D8%A9%20%D8%A7%D9%84%D9%85%D9%87%D8%A7%D9%85%20%D8%A8%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86&amp;updated_after=any&amp;sortby=newest" rel="">من هذه السلسلة</a>، وهو أنواع البيانات خصوصًا القوائم Lists والصفوف tuples.
</p>

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

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

<h2 id="list">
	نوع البيانات list
</h2>

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

<p>
	تبدو القائمة بالشكل الآتي: <code>['cat', 'bat', 'rat', 'elephant']</code> وكما كنّا نكتب السلاسل النصية محاطةً بعلامتَي اقتباس لتحديد متى تبدأ وتنتهي السلسلة النصية، فتبدأ القائمة بقوس مربع وتنتهي بقوس مربع آخر <code>[]</code>. وتسمى القيم داخل القائمة بعناصر القائمة items، ويفصل بين عناصر القائمة بفاصلة. يمكنك إدخال ما يلي في الصدفة التفاعلية للتجربة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_6" style=""><span class="pln">  </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</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="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</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="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span><span class="pln">
   </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</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="str">'hello'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3.1415</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">None</span><span class="pun">,</span><span class="pln"> </span><span class="lit">42</span><span class="pun">]</span><span class="pln">
   </span><span class="pun">[</span><span class="str">'hello'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3.1415</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">None</span><span class="pun">,</span><span class="pln"> </span><span class="lit">42</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"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
   </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span></pre>

<p>
	المتغير <code>spam</code> ➊ له قيمة واحدة، وهي قيمة القائمة، ولكن القائمة نفسها تحتوي على عناصر أخرى. لاحظ أن القيمة <code>[]</code> تعني قائمة فارغة لا تحتوي على قيم مثلها كمثل السلسلة النصية الفارغة ''.
</p>

<h2 id="">
	الوصول إلى عناصر القائمة عبر الفهرس
</h2>

<p>
	لنقل أن لديك القائمة <code>['cat', 'bat', 'rat', 'elephant']</code> مخزنةً في متغير باسم <code>spam</code>، حينها ستكون نتيجة التعبير <code>spam[0]‎</code> هي القيمة <code>'cat'</code> ونتيجة التعبير <code>spam[1]‎</code> هي <code>'bat'</code> وهلم جرًا للبقية.
</p>

<p>
	العدد الصحيح الموجود داخل الأقواس المربعة يسمى فهرسًا index، والقيمة الأولى في القائمة يشار إليها بالفهرس 0، والقيمة الثانية بالفهرس 1، والثالثة بالفهرس 2 …إلخ.
</p>

<p>
	يُظهر الشكل التالي قائمةً مسندةً إلى المتغير <code>spam</code> مع توضيح فهارس كل قيمة فيها. لاحظ أن فهرس العنصر الأول هو 0 ويكون فهرس آخر عنصر مساويًا لطول القائمة ناقص واحد. أي أن الفهرس 3 في قائمةٍ لها أربع قيم يشير إلى آخر عنصر.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150683" href="https://academy.hsoub.com/uploads/monthly_2024_06/000090.jpg.468e01f54a6f32ca2075adee6f8b3f6b.jpg" rel=""><img alt="000090" class="ipsImage ipsImage_thumbnailed" data-fileid="150683" data-unique="srnr5ggxc" src="https://academy.hsoub.com/uploads/monthly_2024_06/000090.jpg.468e01f54a6f32ca2075adee6f8b3f6b.jpg"> </a>
</p>

<p style="text-align: center;">
	الشكل 1: قائمة مخزنة في متغير مع فهارس كل عنصر فيها
</p>

<p>
	على سبيل المثال، أدخل التعابير البرمجية الآتية في الصدفة التفاعلية وابدأ بضبط قيمة المتغير <code>spam</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_8" style=""><span class="pln">   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
   </span><span class="str">'cat'</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
   </span><span class="str">'bat'</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[</span><span class="lit">2</span><span class="pun">]</span><span class="pln">
   </span><span class="str">'rat'</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[</span><span class="lit">3</span><span class="pun">]</span><span class="pln">
   </span><span class="str">'elephant'</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">][</span><span class="lit">3</span><span class="pun">]</span><span class="pln">
   </span><span class="str">'elephant'</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="str">'Hello, '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> spam</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
</span><span class="pun">➋</span><span class="pln"> </span><span class="str">'Hello, cat'</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'The '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> spam</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="str">' ate the '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> spam</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'.'</span><span class="pln">
   </span><span class="str">'The bat ate the cat.'</span></pre>

<p>
	لاحظ أن نتيجة التعبير ‎'Hello, ' + spam[0]<code>➊‎ هي 'Hello, ' + 'cat'</code> ذلك لأن نتيجة <code>spam[0]‎</code> هي <code>'cat'</code>, وبالنهاية ستكون نتيجة التعبير هي <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>'Hello, cat'</code> ➋.
</p>

<p>
	ستحصل على رسالة الخطأ IndexError إذا استخدمت فهرسًا يتجاوز عدد عناصر القائمة.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_10" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[</span><span class="lit">10000</span><span class="pun">]</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#9&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    spam</span><span class="pun">[</span><span class="lit">10000</span><span class="pun">]</span><span class="pln">
</span><span class="typ">IndexError</span><span class="pun">:</span><span class="pln"> list index out of range</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_12" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
</span><span class="str">'bat'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[</span><span class="lit">1.0</span><span class="pun">]</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#13&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    spam</span><span class="pun">[</span><span class="lit">1.0</span><span class="pun">]</span><span class="pln">
</span><span class="typ">TypeError</span><span class="pun">:</span><span class="pln"> list indices must be integers </span><span class="kwd">or</span><span class="pln"> slices</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> float
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[</span><span class="pln">int</span><span class="pun">(</span><span class="lit">1.0</span><span class="pun">)]</span><span class="pln">
</span><span class="str">'bat'</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_14" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">],</span><span class="pln"> </span><span class="pun">[</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">20</span><span class="pun">,</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln"> </span><span class="lit">40</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</span><span class="pun">]]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
</span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[</span><span class="lit">0</span><span class="pun">][</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
</span><span class="str">'bat'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</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="pln">
</span><span class="lit">50</span></pre>

<p>
	يدل الفهرس الأول على أي عنصر من القائمة الأولى يجب استخدامه، والفهرس الثاني يدل على العنصر الموجود في القائمة الثانية، فمثلًا <code>spam[0][1]‎</code> يطبع <code>'bat'</code>، وهي القيمة الثانية من القائمة الموجودة في الفهرس الأول. وإذا استخدمت فهرسًا واحدًا فسيطبع البرنامج القائمة الموجودة في ذلك الفهرس كاملةً.
</p>

<h2 id="-1">
	الفهارس السالبة
</h2>

<p>
	صحيحٌ أن أرقام الفهارس تبدًا من <code>0</code>، لكنك تستطيع استخدام الأعداد الصحيحة السالبة قيمًا للفهارس. فالقيمة <code>‎-1</code> تشير إلى آخر عنصر في القائمة، والقيمة <code>‎-2</code> تشير إلى العنصر ما قبل الأخير …إلخ. جرب ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_16" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[-</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
</span><span class="str">'elephant'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[-</span><span class="lit">3</span><span class="pun">]</span><span class="pln">
</span><span class="str">'bat'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'The '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> spam</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="str">' is afraid of the '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> spam</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="str">'.'</span><span class="pln">
</span><span class="str">'The elephant is afraid of the bat.'</span></pre>

<h2 id="slice">
	الحصول على قائمة من قائمة أخرى عبر التقطيع slice
</h2>

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

<ul>
	<li>
		<code>spam[2]‎</code> ينتج عنصرًا واحدًا موجودًا في الفهرس المحدد.
	</li>
	<li>
		spam[1:4]<code>‎</code> ينتج قائمة فيها أكثر من عنصر.
	</li>
</ul>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_18" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</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="pln">
</span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</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="pun">[</span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[</span><span class="lit">0</span><span class="pun">:-</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
</span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">]</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_20" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[:</span><span class="lit">2</span><span class="pun">]</span><span class="pln">
</span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[</span><span class="lit">1</span><span class="pun">:]</span><span class="pln">
</span><span class="pun">[</span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">[:]</span><span class="pln">
</span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span></pre>

<h2 id="len">
	الحصول على طول القائمة عبر الدالة len()‎
</h2>

<p>
	ستعيد الدالة <code>len()‎</code> عدد عناصر قائمة تُمرَّر إليها، وهي تشبه إحصاء عدد المحارف في سلسلة نصية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_22" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dog'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'moose'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">spam</span><span class="pun">)</span><span class="pln">
</span><span class="lit">3</span></pre>

<h2 id="-2">
	تغيير القيم في قائمة عبر الفهارس
</h2>

<p>
	تعودنا أن قيمة المتغير تكون على يسار عامل الإسناد، كما في <code>spam = 42</code>، ويمكننا فعل المثل مع القوائم بكتابة فهرس العنصر الذي نريد تغيير قيمته، مثلًا <code>spam[1] = 'aardvark'‎</code> يعني «أسند القيمة الموجودة في الفهرس 1 في القائمة <code>spam</code> إلى السلسلة النصية <code>'aardvark'</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_26" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</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="str">'aardvark'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'aardvark'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</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"> spam</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'aardvark'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'aardvark'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</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="lit">12345</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'aardvark'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'aardvark'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">12345</span><span class="pun">]</span></pre>

<h2 id="concatenationreplication">
	جمع القوائم Concatenation وتكرارها Replication
</h2>

<p>
	يمكن أن تجمع <a href="https://wiki.hsoub.com/Python/list" rel="external">القوائم</a> وتكرر كما في السلاسل النصية، فالعامل <code>+</code> يجمع بين قائمتين لإنشاء قائمة جديدة، والعامل <code>*</code> يستخدم لتكرار سلسلة نصية عددًا من المرات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_28" style=""><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</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="pun">[</span><span class="str">'A'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'B'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'C'</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="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</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">'B'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'C'</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="str">'X'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Y'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Z'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
</span><span class="pun">[</span><span class="str">'X'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Y'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Z'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'X'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Y'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Z'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'X'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Y'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Z'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </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="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> spam </span><span class="pun">+</span><span class="pln"> </span><span class="pun">[</span><span class="str">'A'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'B'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'C'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</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">'B'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'C'</span><span class="pun">]</span></pre>

<h2 id="del">
	إزالة القيم من القوائم عبر عبارة del
</h2>

<p>
	تستخدم العبارة <code>del</code> لحذف قيم معينة من قائمة. جميع القيم الموجودة في القائمة بعد العنصر المحذوف سيتغير فهرسها ويصبح أقل بمقدار <code>1</code>. مثلًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_30" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">del</span><span class="pln"> spam</span><span class="pun">[</span><span class="lit">2</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">del</span><span class="pln"> spam</span><span class="pun">[</span><span class="lit">2</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">]</span></pre>

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

<h2 id="-3">
	التعامل مع القوائم
</h2>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_32" style=""><span class="pln">catName1 </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Zophie'</span><span class="pln">
catName2 </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Pooka'</span><span class="pln">
catName3 </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Simon'</span><span class="pln">
catName4 </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Lady Macbeth'</span><span class="pln">
catName5 </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Fat-tail'</span><span class="pln">
catName6 </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Miss Cleo'</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_34" style=""><span class="kwd">print</span><span class="pun">(</span><span class="str">'Enter the name of cat 1:'</span><span class="pun">)</span><span class="pln">
catName1 </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Enter the name of cat 2:'</span><span class="pun">)</span><span class="pln">
catName2 </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Enter the name of cat 3:'</span><span class="pun">)</span><span class="pln">
catName3 </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Enter the name of cat 4:'</span><span class="pun">)</span><span class="pln">
catName4 </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Enter the name of cat 5:'</span><span class="pun">)</span><span class="pln">
catName5 </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Enter the name of cat 6:'</span><span class="pun">)</span><span class="pln">
catName6 </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'The cat names are:'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">catName1 </span><span class="pun">+</span><span class="pln"> </span><span class="str">' '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> catName2 </span><span class="pun">+</span><span class="pln"> </span><span class="str">' '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> catName3 </span><span class="pun">+</span><span class="pln"> </span><span class="str">' '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> catName4 </span><span class="pun">+</span><span class="pln"> </span><span class="str">' '</span><span class="pln"> </span><span class="pun">+</span><span class="pln">
catName5 </span><span class="pun">+</span><span class="pln"> </span><span class="str">' '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> catName6</span><span class="pun">)</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_36" style=""><span class="pln">catNames </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="kwd">True</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Enter the name of cat '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">len</span><span class="pun">(</span><span class="pln">catNames</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="pun">+</span><span class="pln">
      </span><span class="str">' (Or enter nothing to stop.):'</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="pln">
    </span><span class="kwd">if</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">break</span><span class="pln">
    catNames </span><span class="pun">=</span><span class="pln"> catNames </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">  </span><span class="com"># جمع القوائم</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'The cat names are:'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> name </span><span class="kwd">in</span><span class="pln"> catNames</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'  '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> name</span><span class="pun">)</span></pre>

<p>
	ناتج تجربة المثال السابق:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_38" style=""><span class="typ">Enter</span><span class="pln"> the name of cat </span><span class="lit">1</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Or</span><span class="pln"> enter nothing to stop</span><span class="pun">.):</span><span class="pln">
</span><span class="typ">Zophie</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> the name of cat </span><span class="lit">2</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Or</span><span class="pln"> enter nothing to stop</span><span class="pun">.):</span><span class="pln">
</span><span class="typ">Pooka</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> the name of cat </span><span class="lit">3</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Or</span><span class="pln"> enter nothing to stop</span><span class="pun">.):</span><span class="pln">
</span><span class="typ">Simon</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> the name of cat </span><span class="lit">4</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Or</span><span class="pln"> enter nothing to stop</span><span class="pun">.):</span><span class="pln">
</span><span class="typ">Lady</span><span class="pln"> </span><span class="typ">Macbeth</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> the name of cat </span><span class="lit">5</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Or</span><span class="pln"> enter nothing to stop</span><span class="pun">.):</span><span class="pln">
</span><span class="typ">Fat</span><span class="pun">-</span><span class="pln">tail
</span><span class="typ">Enter</span><span class="pln"> the name of cat </span><span class="lit">6</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Or</span><span class="pln"> enter nothing to stop</span><span class="pun">.):</span><span class="pln">
</span><span class="typ">Miss</span><span class="pln"> </span><span class="typ">Cleo</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> the name of cat </span><span class="lit">7</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Or</span><span class="pln"> enter nothing to stop</span><span class="pun">.):</span><span class="pln">

</span><span class="typ">The</span><span class="pln"> cat names are</span><span class="pun">:</span><span class="pln">
  </span><span class="typ">Zophie</span><span class="pln">
  </span><span class="typ">Pooka</span><span class="pln">
  </span><span class="typ">Simon</span><span class="pln">
  </span><span class="typ">Lady</span><span class="pln"> </span><span class="typ">Macbeth</span><span class="pln">
  </span><span class="typ">Fat</span><span class="pun">-</span><span class="pln">tail
  </span><span class="typ">Miss</span><span class="pln"> </span><span class="typ">Cleo</span></pre>

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

<h3 id="for">
	استخدام حلقات for مع القوائم
</h3>

<p>
	تعلمنا في المقال الثاني من هذه السلسلة عن حلقات التكرار <code>for</code> لتنفيذ كتلة من الشيفرات لعدد معين من المرات؛ لكن تقنيًا ما تفعله <code>for</code> هو تكرار الشيفرة داخلها مرةً واحدةً لكل عنصر من عناصر القائمة. فالشيفرة:
</p>

<pre class="ipsCode">for i in range(4):
    print(i)
</pre>

<p>
	ستخرج الناتج الآتي:
</p>

<pre class="ipsCode" id="ips_uid_5983_79">0
1
2
3</pre>

<p>
	هذا لأن القيمة المعادة من تنفيذ <code>range(4)‎</code> هي قيمة متسلسلة sequence value التي تعاملها بايثون معاملةً شبيهة بالقائمة <code>‎[0, 1, 2, 3]‎</code> (سنشرح المتسلسلات Sequences لاحقًا في هذا المقال). سيكون ناتج البرنامج السابق مماثلًا تمامًا لما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_42" style=""><span class="kwd">for</span><span class="pln"> i </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">[</span><span class="lit">0</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">2</span><span class="pun">,</span><span class="pln"> </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">i</span><span class="pun">)</span></pre>

<p>
	<a href="https://wiki.hsoub.com/Python/for" rel="external">حلقة التكرار for</a> السابقة تمر على جميع عناصر القائمة <code>‎[0, 1, 2, 3]‎</code> وتضبط قيمة المتغير <code>i</code> إلى قيمة كل عنصر منها.
</p>

<p>
	من الشائع استخدام التعبير <code>range(len(someList))‎</code> مع حلقة التكرار <code>for</code> في <a href="https://academy.hsoub.com/programming/python/%D9%85%D9%85%D9%8A%D8%B2%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86/" rel="">بايثون</a> للمرور على جميع عناصر قائمة ما:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_44" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> supplies </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'pens'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'staplers'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'flamethrowers'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'binders'</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"> i </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="pln">len</span><span class="pun">(</span><span class="pln">supplies</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="str">'Index '</span><span class="pln"> </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="str">' in supplies is: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> supplies</span><span class="pun">[</span><span class="pln">i</span><span class="pun">])</span><span class="pln">

</span><span class="typ">Index</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> supplies </span><span class="kwd">is</span><span class="pun">:</span><span class="pln"> pens
</span><span class="typ">Index</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> supplies </span><span class="kwd">is</span><span class="pun">:</span><span class="pln"> staplers
</span><span class="typ">Index</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> supplies </span><span class="kwd">is</span><span class="pun">:</span><span class="pln"> flamethrowers
</span><span class="typ">Index</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> supplies </span><span class="kwd">is</span><span class="pun">:</span><span class="pln"> binders</span></pre>

<p>
	استخدام <code>range(len(supplies))‎</code> في المثال السابق مناسب لأن الشيفرة داخل الحلقة تستطيع الوصول إلى الفهرس عبر المتغير i وإلى القيمة المرتبطة بذاك الفهرس عبر <code>supplies[i]‎</code>، والأفضل من ذلك كله أن <code>range(len(supplies))‎</code> ستؤدي إلى المرور على جميع عناصر القائمة بغض النظر عن عددها.
</p>

<h3 id="innotin">
	العاملان in و not in
</h3>

<p>
	يمكنك معرفة إن كانت قيمةٌ ما موجودةً -أو غير موجودةٍ- في قائمة ما باستخدام العاملين in و not in. وكما في بقية العوامل، يستعمل العاملان <code>in</code> و <code>not in</code> في التعابير وتربطان قيمتين: قيمة نرغب بالبحث عنها في القائمة والقائمة التي نرغب بالبحث فيها؛ وتكون نتيجة هذه التعابير <a href="https://wiki.hsoub.com/Python/boolean" rel="external">قيمة منطقية بوليانية</a>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_46" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'howdy'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">[</span><span class="str">'hello'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'hi'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'howdy'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'heyas'</span><span class="pun">]</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'hello'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'hi'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'howdy'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'heyas'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'cat'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> spam
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'howdy'</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> spam
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'cat'</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> spam
</span><span class="kwd">True</span></pre>

<p>
	فمثلًا يسمح البرنامج الآتي للمستخدم بكتابة اسم قطته ليتأكد إن كان اسمها ضمن قائمة من أسماء القطط. احفظه باسم <code>myPets.py</code> وجربه:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_48" style=""><span class="pln">myPets </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Zophie'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Pooka'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Fat-tail'</span><span class="pun">]</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Enter a pet name:'</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="pln">
</span><span class="kwd">if</span><span class="pln"> name </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> myPets</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'I do not have a pet named '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> name</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">name </span><span class="pun">+</span><span class="pln"> </span><span class="str">' is my pet.'</span><span class="pun">)</span></pre>

<p>
	سيشبه الناتج ما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_50" style=""><span class="typ">Enter</span><span class="pln"> a pet name</span><span class="pun">:</span><span class="pln">
</span><span class="typ">Footfoot</span><span class="pln">
I </span><span class="kwd">do</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> have a pet named </span><span class="typ">Footfoot</span></pre>

<h3 id="-4">
	خدعة للإسناد المتعدد
</h3>

<p>
	هنالك اختصار يسمى تقنيًا بنشر الصفوف tuple unpacking يسمح لنا بإسناد عدة قيمة لمتغيرات اعتمادًا على قائمة في سطر واحد. فبدلًا من كتابة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_52" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> cat </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'fat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'gray'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'loud'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> size </span><span class="pun">=</span><span class="pln"> cat</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> color </span><span class="pun">=</span><span class="pln"> cat</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> disposition </span><span class="pun">=</span><span class="pln"> cat</span><span class="pun">[</span><span class="lit">2</span></pre>

<p>
	نستطيع أن نكتب:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_54" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> cat </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'fat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'gray'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'loud'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> size</span><span class="pun">,</span><span class="pln"> color</span><span class="pun">,</span><span class="pln"> disposition </span><span class="pun">=</span><span class="pln"> cat</span></pre>

<p>
	يجب أن يكون عدد المتغيرات وطول القائمة متساوٍ تمامًا، وإلا فستعطيك بايثون الخطأ ValueError:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_56" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> cat </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'fat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'gray'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'loud'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> size</span><span class="pun">,</span><span class="pln"> color</span><span class="pun">,</span><span class="pln"> disposition</span><span class="pun">,</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> cat
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#84&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    size</span><span class="pun">,</span><span class="pln"> color</span><span class="pun">,</span><span class="pln"> disposition</span><span class="pun">,</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> cat
</span><span class="typ">ValueError</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> enough values to unpack </span><span class="pun">(</span><span class="pln">expected </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> got </span><span class="lit">3</span><span class="pun">)</span></pre>

<h3 id="enumerate">
	استخدام الدالة enumerate()‎ مع القوائم
</h3>

<p>
	بدلًا من استخدام <code>range(len(someList))‎</code> مع حلقة تكرار <code>for</code> للوصول إلى قيمة الفهرس لكل عنصر من عناصر القائمة، فيمكننا استدعاء الدالة enumerate()<code>‎</code> بدلًا منها.
</p>

<p>
	ففي كل دورة <a href="https://wiki.hsoub.com/Python/looping_techniques" rel="external">لحلقة التكرار</a> ستعيد الدالة <code>enumerate()‎</code> قيمتين: فهرس العنصر الموجود في القائمة والعنصر نفسه على شكل قائمة. فالشيفرة الآتية مماثلة في الوظيفة للمثال الموجود في قسم «استخدام حلقات <code>for</code> مع القوائم»:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_58" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> supplies </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'pens'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'staplers'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'flamethrowers'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'binders'</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"> index</span><span class="pun">,</span><span class="pln"> item </span><span class="kwd">in</span><span class="pln"> enumerate</span><span class="pun">(</span><span class="pln">supplies</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="str">'Index '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</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="str">' in supplies is: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> item</span><span class="pun">)</span><span class="pln">

</span><span class="typ">Index</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> supplies </span><span class="kwd">is</span><span class="pun">:</span><span class="pln"> pens
</span><span class="typ">Index</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> supplies </span><span class="kwd">is</span><span class="pun">:</span><span class="pln"> staplers
</span><span class="typ">Index</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> supplies </span><span class="kwd">is</span><span class="pun">:</span><span class="pln"> flamethrowers
</span><span class="typ">Index</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> supplies </span><span class="kwd">is</span><span class="pun">:</span><span class="pln"> binders</span></pre>

<p>
	الدالة <code>enumerate()‎</code> مفيدة إن كنت تريد الوصول إلى العنصر وفهرسه ضمن حلقة التكرار.
</p>

<h3 id="randomchoicerandomshuffle">
	استخدام الدالتين random.choice()‎ و random.shuffle()‎ مع القوائم
</h3>

<p>
	الوحدة random فيها عدة دوال تقبل القوائم كمعاملات لها. الدالة <code>random.choice()‎</code> تعيد عنصرًا مختارًا عشوائيًا من القائمة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_60" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> random
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> pets </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Dog'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Moose'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">choice</span><span class="pun">(</span><span class="pln">pets</span><span class="pun">)</span><span class="pln">
</span><span class="str">'Dog'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">choice</span><span class="pun">(</span><span class="pln">pets</span><span class="pun">)</span><span class="pln">
</span><span class="str">'Cat'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">choice</span><span class="pun">(</span><span class="pln">pets</span><span class="pun">)</span><span class="pln">
</span><span class="str">'Cat'</span></pre>

<p>
	يمكنك أن تقول أن <code>random.choice(someList)‎</code> هي نسخة مختصرة من <code>someList[random.randint(0, len(someList) – 1]‎</code>. الدالة <code>random.shuffle()‎</code> تعيد ترتيب العناصر ضمن القائمة عشوائيًا، وتعدل القائمة مباشرة دون إعادة قائمة جديدة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_62" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> random
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> people </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Alice'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Bob'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Carol'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'David'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">shuffle</span><span class="pun">(</span><span class="pln">people</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> people
</span><span class="pun">[</span><span class="str">'Carol'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'David'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Alice'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Bob'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">shuffle</span><span class="pun">(</span><span class="pln">people</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> people
</span><span class="pun">[</span><span class="str">'Alice'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'David'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Bob'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Carol'</span><span class="pun">]</span></pre>

<h3 id="-5">
	عوامل الإسناد المحسنة
</h3>

<p>
	من الشائع حين إسناد قيمة ما إلى متغير أن تستعمل قيمة المتغير الابتدائية أساسًا للقيمة الجديدة. فمثلًا بعد إسنادك القيمة <code>42</code> للمتغير <code>spam</code> وأردت زيادة قيمة المتغير بمقدار واحد:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_64" style=""><span class="pun">&gt;&gt;&gt;</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="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> spam </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="lit">43</span></pre>

<p>
	يمكنك بدلًا من ذلك استخدام عامل الإسناد المحسن ‎<code>+=</code>‎ لنفس النتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_66" style=""><span class="pun">&gt;&gt;&gt;</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="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="lit">43</span></pre>

<p>
	هنالك عوامل إسناد محسنة للعوامل <code>+</code> و <code>-</code> و <code>*</code> و<code>/</code> و <code>%</code> موضحة في الجدول التالي:
</p>

<table>
	<thead>
		<tr>
			<th>
				عامل الإسناد المحسن
			</th>
			<th>
				التعبير البرمجي المكافئ
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				spam += 1
			</td>
			<td>
				spam = spam + 1
			</td>
		</tr>
		<tr>
			<td>
				spam -= 1
			</td>
			<td>
				spam = spam - 1
			</td>
		</tr>
		<tr>
			<td>
				spam <code>*</code>= 1
			</td>
			<td>
				spam = spam <code>*</code> 1
			</td>
		</tr>
		<tr>
			<td>
				spam /= 1
			</td>
			<td>
				spam = spam / 1
			</td>
		</tr>
		<tr>
			<td>
				spam %= 1
			</td>
			<td>
				spam = spam % 1
			</td>
		</tr>
	</tbody>
</table>

<p style="text-align: center;">
	الجدول 1: عوامل الأسناد المحسنة
</p>

<p>
	يمكن استخدام عامل الإسناد المحسن <code>‎</code>+=‎ لدمج قائمتين، والمعامل ‎<code>*=</code>‎ لتكرار قائمة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_69" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Hello,'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">+=</span><span class="pln"> </span><span class="str">' world!'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="str">'Hello world!'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> olive </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Zophie'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> olive </span><span class="pun">*=</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> olive
</span><span class="pun">[</span><span class="str">'Zophie'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Zophie'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Zophie'</span><span class="pun">]</span></pre>

<h2 id="methods">
	التوابع Methods
</h2>

<p>
	يمكننا القول مجازًا أن التابع method يكافئ الدوال لكنها «تستدعى على» قيمة ما. فمثلًا إذا استدعيت دالة القوائم index()<code>‎</code> -التي سنشرحها بعد قليل- على قائمة فستكتب: <code>list.index('hello')‎</code>؛ أي أن التابع يأتي بعد القيمة ويفصل عنها بنقطة.
</p>

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

<h3 id="index">
	العثور على قيمة في قائمة عبر التابع index()‎
</h3>

<p>
	تمتلك القوائم التابع <code>index()‎</code> الذي تقبل معاملًا وهو القيمة التي سيجري البحث عنها في القائمة، وإذا كان العنصر موجودًا فسيعاد فهرس ذاك العنصر، وإذا لم يكن موجودًا فستطلق <a href="https://wiki.hsoub.com/Python" rel="external">بايثون</a> الخطأ ValueError:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_71" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'hello'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'hi'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'howdy'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'heyas'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">index</span><span class="pun">(</span><span class="str">'hello'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">0</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">index</span><span class="pun">(</span><span class="str">'heyas'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">3</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">index</span><span class="pun">(</span><span class="str">'howdy howdy howdy'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#31&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    spam</span><span class="pun">.</span><span class="pln">index</span><span class="pun">(</span><span class="str">'howdy howdy howdy'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">ValueError</span><span class="pun">:</span><span class="pln"> </span><span class="str">'howdy howdy howdy'</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> list</span></pre>

<p>
	وعند وجود قيم مكررة في القائمة فسيعاد الفهرس لأول قيمة يُعثَر عليها، لاحظ أن التابع index()<code>‎</code> قد أعاد 1 وليس 3 في هذا المثال:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_73" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Zophie'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Pooka'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Fat-tail'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Pooka'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">index</span><span class="pun">(</span><span class="str">'Pooka'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">1</span></pre>

<h3 id="appendinsert">
	إضافة قيم إلى القوائم عبر append()‎ و insert()‎
</h3>

<p>
	استخدم التابعين append()<code>‎</code> و <code>insert()‎</code> لإضافة قيم جديدة إلى قائمة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_75" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dog'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="str">'moose'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dog'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'moose'</span><span class="pun">]</span></pre>

<p>
	أدى استدعاء التابع <code>append()‎</code> إلى إضافة قيمة المعامل الممرر إليه إلى نهاية القائمة.
</p>

<p>
	التابع <code>insert()‎</code> يضيف قيمةً جديدةً إلى أي فهرس في القائمة، ويكون الوسيط الأول الممرر إلى التابع <code>insert()‎</code> هو فهرس القيمة الجديدة، والوسيط الثاني هو القيمة التي نريد إضافتها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_77" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dog'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">insert</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="str">'chicken'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'chicken'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dog'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">]</span></pre>

<p>
	لاحظ أن الشيفرة التي كتبناها هي <code>spam.append('moose')‎</code> و <code>spam.insert(1, 'chicken')‎</code> وليست <code>spam = spam.append('moose')‎</code> أو <code>spam = spam.insert(1, 'chicken')‎</code>، إذ لا يعيد التابع <code>append()‎</code> أو <code>insert()‎</code> القيمة الجديدة للقائمة <code>spam</code> (وفي الواقع تكون نتيجة استدعائها هي <code>None</code>، فلا حاجة إلى تخزين قيمة استدعاء تلك التوابع في متغير، بل تعدل تلك التوابع القائمةَ مباشرةً. سنتحدث بالتفصيل عن القوائم القابلة للتغيير وغير القابلة للتغيير لاحقًا في هذا المقال.
</p>

<p>
	التوابع التي ترتبط بنوع بيانات محدد -مثل <code>append()‎</code> و <code>insert()‎</code>- هي خاصة بذاك النوع، فلا يمكن استخدامها على قيم أخرى مثل السلاسل النصية أو الأعداد الصحيحة. لاحظ ظهور رسالة الخطأ AttributeError في المثال الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_82" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggs </span><span class="pun">=</span><span class="pln"> </span><span class="str">'hello'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggs</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="str">'world'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#19&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    eggs</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="str">'world'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">AttributeError</span><span class="pun">:</span><span class="pln"> </span><span class="str">'str'</span><span class="pln"> object has no attribute </span><span class="str">'append'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> olive </span><span class="pun">=</span><span class="pln"> </span><span class="lit">42</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> olive</span><span class="pun">.</span><span class="pln">insert</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="str">'world'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#22&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    olive</span><span class="pun">.</span><span class="pln">insert</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="str">'world'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">AttributeError</span><span class="pun">:</span><span class="pln"> </span><span class="str">'int'</span><span class="pln"> object has no attribute </span><span class="str">'insert'</span></pre>

<h3 id="remove">
	إزالة القيم من القوائم عبر التابع remove()‎
</h3>

<p>
	نمرر إلى التابع <code>remove()‎</code> القيمة التي نريد حذفها من القائمة التي يستدعى التابع عليها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_84" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">remove</span><span class="pun">(</span><span class="str">'bat'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span></pre>

<p>
	إذا حاولنا حذف قيمة غير موجودة في القائمة فسيظهر الخطأ ValueError:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_86" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephant'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">remove</span><span class="pun">(</span><span class="str">'chicken'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#11&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    spam</span><span class="pun">.</span><span class="pln">remove</span><span class="pun">(</span><span class="str">'chicken'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">ValueError</span><span class="pun">:</span><span class="pln"> list</span><span class="pun">.</span><span class="pln">remove</span><span class="pun">(</span><span class="pln">x</span><span class="pun">):</span><span class="pln"> x </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> list</span></pre>

<p>
	إذا تكررت القيمة التي نريد حذفها أكثر من مرة في القائمة فستزال أول نسخة من تلك القيمة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_88" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'hat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cat'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">remove</span><span class="pun">(</span><span class="str">'cat'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="pun">[</span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'hat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cat'</span><span class="pun">]</span></pre>

<p>
	لاحظ أن العبارة <code>del</code> مفيدة حينما تعرف فهرس العنصر الذي تريد حذفه من القائمة، بينما يفيد التابع <code>remove()‎</code> إذا كنت تعرف قيمة العنصر الذي تريد حذفه.
</p>

<h3 id="sort">
	ترتيب عناصر قائمة عبر التابع sort()‎
</h3>

<p>
	يمكن ترتيب القوائم التي تحتوي على أعداد أو على سلاسل نصية باستخدام التابع <code>sort()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_90" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3.14</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="lit">7</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="pun">[-</span><span class="lit">7</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">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3.14</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'ants'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cats'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dogs'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'badgers'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephants'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="pun">[</span><span class="str">'ants'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'badgers'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cats'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dogs'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'elephants'</span><span class="pun">]</span></pre>

<p>
	يمكنك تمرير القيمة <code>True</code> قيمةً للوسيط المسمى reverse لجعل التابع<code>sort()‎</code> يرتب النتائج ترتيبًا عكسيًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_92" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">(</span><span class="pln">reverse</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="pun">[</span><span class="str">'elephants'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dogs'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cats'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'badgers'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'ants'</span><span class="pun">]</span></pre>

<p>
	هنالك ثلاثة أمور أساسية يجب عليك معرفتها حول التابع <code>sort()‎</code>: بدايةً يرتب التابع <code>sort()‎</code> عناصر القائمة مباشرةً دون إعادة قائمة جديدة، أي ليس هنالك فائدة من كتابة شيء يشبه <code>spam = spam.sort()‎</code>.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_94" style=""><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </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="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Alice'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Bob'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">()</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#70&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    spam</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">()</span><span class="pln">
</span><span class="typ">TypeError</span><span class="pun">:</span><span class="pln"> </span><span class="str">'&lt;'</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> supported between instances of </span><span class="str">'str'</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="str">'int'</span></pre>

<p>
	وأخيرًا، يستعمل التابع <code>sort()‎</code> ترتيب ASCII للسلاسل النصية بدلًا من الترتيب الهجائي، هذا يعني أن الأحرف الكبيرة في الإنكليزية تأتي قبل الأحرف الصغيرة أي أن a سيكون بعد Z مباشرةً:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_96" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Alice'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'ants'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Bob'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'badgers'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Carol'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cats'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="pun">[</span><span class="str">'Alice'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Bob'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Carol'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'ants'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'badgers'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cats'</span><span class="pun">]</span></pre>

<p>
	إذا أردت ترتيب القيم ترتيبًا هجائيًا، فمرر القيمة <code>str.lower</code> للوسيط المسمى <code>key</code> في التابع <code>sort()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_98" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'a'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'z'</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">'Z'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">(</span><span class="pln">key</span><span class="pun">=</span><span class="pln">str</span><span class="pun">.</span><span class="pln">lower</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="pun">[</span><span class="str">'a'</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">'z'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Z'</span><span class="pun">]</span></pre>

<p>
	هذا سيجعل التابع sort()‎ يتعامل مع جميع عناصر القائمة كما لو أنها في حالة الأحرف الصغيرة دون تعديل القيم نفسها.
</p>

<h3 id="reverse">
	قلب ترتيب عناصر قائمة عبر التابع reverse()‎
</h3>

<p>
	إذا احتجت إلى قلب ترتيب عناصر إحدى القوائم سريعًا فاستعمل التابع reverse()<code>‎</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_100" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dog'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'moose'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam</span><span class="pun">.</span><span class="pln">reverse</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="pun">[</span><span class="str">'moose'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dog'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cat'</span><span class="pun">]</span></pre>

<p>
	وكما في التابع sort()‎، لا يعيد التابع <code>reverse()‎</code> قائمةً بل يعدلها مباشرةً، ولهذا نكتب <code>spam.reverse()‎</code> وليس <code>spam = spam.reverse()‎</code>.
</p>

<h4 id="-6">
	استثناءات من قواعد المسافات البادئة في بايثون
</h4>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_104" style=""><span class="pln">spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'apples'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'oranges'</span><span class="pun">,</span><span class="pln">
                    </span><span class="str">'bananas'</span><span class="pun">,</span><span class="pln">
</span><span class="str">'cats'</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></pre>

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

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_107" style=""><span class="kwd">print</span><span class="pun">(</span><span class="str">'Four score and seven '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> \
      </span><span class="str">'years ago...'</span><span class="pun">)</span></pre>

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

<h2 id="-7">
	مثال عملي: إعادة كتابة برنامج الكرة السحرية باستخدام القوائم
</h2>

<p>
	يمكننا كتابة نسخة أفضل من مثال الكرة السحرية الذي كتبناه عبر عبارات <code>elif</code> سابقًا، إذ يمكننا إنشاء قائمة واحدة وسنجعل البرنامج يتعامل معها مباشرةً. احفظ ما يلي في ملف باسم <code>magic8ball2.py</code>:
</p>

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

messages </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'It is certain'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'It is decidedly so'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'Yes definitely'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'Reply hazy try again'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'Ask again later'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'Concentrate and ask again'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'My reply is no'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'Outlook not so good'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'Very doubtful'</span><span class="pun">]</span><span class="pln">

</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">messages</span><span class="pun">[</span><span class="pln">random</span><span class="pun">.</span><span class="pln">randint</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">messages</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></pre>

<p>
	حينما تجرب هذا البرنامج فسيبدو ناتجه كما في المثال <code>magic8ball.py</code> الأصلي.
</p>

<p>
	لاحظ التعبير الذي استخدمناه كفهرس للقائمة <code>messages:‏ random.randint (0, len(messages) - 1)‎</code>. وهو يولد عدد عشوائيًا نستعمله كفهرس بغض النظر عن عدد العناصر الموجودة في القائمة <code>messages</code>.
</p>

<p>
	ذاك التعبير يولد قيمةً عشوائيًا بين <code>0</code> وقيمة <code>len(messages) - 1</code>، والقائدة من هذه الطريقة أننا نستطيع إضافة وإزالة العناصر من القائمة <code>messages</code> دون الحاجة إلى تغيير أي شيفرات أخرى، فعندما تحدث شيفرة البرنامج مستقبلًا لإضافة عناصر جديدة إلى القائمة، فلا تضطر إلى تعديلات إضافية، وكلما قللت من الأمور التي تغيرها قلَّت احتمالية استحداث <a 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> جديدة.
</p>

<h2 id="sequencedatatypes">
	أنواع البيانات المتسلسلة Sequence Data Types
</h2>

<p>
	القوائم هي إحدى أنواع البيانات التي تمثل قائمةً من القيم، لكنها ليست الوحيدة. فمثلًا <a href="https://wiki.hsoub.com/Python/str" rel="external">السلاسل النصية strings</a> والقوائم lists متشابهة جدًا إذا تخيلنا أن السلسلة النصية هي «قائمة» من المحارف.
</p>

<p>
	أنواع البيانات المتسلسلة في بايثون تتضمن القوائم lists، والسلاسل النصية strings، وكائنات المجالات range objects المعادة من الدالة range()<code>‎</code>، <a href="https://wiki.hsoub.com/Python/tuples" rel="external">والصفوف tuples</a>.
</p>

<p>
	أغلبية الأمور التي تستطيع فعلها مع القوائم يمكنك فعلها مع بقية أنواع البيانات المتسلسلة، بما في ذلك: الفهرسة، والتقطيع، واستخدامها مع حلقات <code>for</code>، واستخدام <code>len()‎</code>، واستخدام العوامل <code>in</code> و <code>not in</code>.
</p>

<p>
	جرب المثال الآتي لترى ذلك عمليًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_111" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Zophie'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> name</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
</span><span class="str">'Z'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> name</span><span class="pun">[-</span><span class="lit">2</span><span class="pun">]</span><span class="pln">
</span><span class="str">'i'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> name</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="pln">
</span><span class="str">'Zoph'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Zo'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> name
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'z'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> name
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'p'</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> name
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> i </span><span class="kwd">in</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">print</span><span class="pun">(</span><span class="str">'* * * '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> i </span><span class="pun">+</span><span class="pln"> </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"> Z </span><span class="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"> o </span><span class="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"> p </span><span class="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"> h </span><span class="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"> i </span><span class="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"> e </span><span class="pun">*</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">*</span></pre>

<h2 id="-8">
	أنواع البيانات القابلة وغير القابلة للتعديل
</h2>

<p>
	تختلف القوائم والسلاسل النصية عن بعضها اختلافًا جوهريًا، فالقوائم هي من أنواع البيانات القابلة للتعديل mutable data type، فيمكن أن تضاف أو تحذف أو تعدل عناصرها؛ بينما السلاسل النصية غير قابلة للتعديل immutable، فإذا حاولت ضبط قيمة أحد محارف السلسلة النصية يدويًا فسيحدث الخطأ TypeError كما في المثال الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_113" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Zophie a cat'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> name</span><span class="pun">[</span><span class="lit">7</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'the'</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#50&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    name</span><span class="pun">[</span><span class="lit">7</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'the'</span><span class="pln">
</span><span class="typ">TypeError</span><span class="pun">:</span><span class="pln"> </span><span class="str">'str'</span><span class="pln"> object does </span><span class="kwd">not</span><span class="pln"> support item assignment</span></pre>

<p>
	الطريقة المعتمدة «لتعديل» سلسلة نصية هي استخدام التقطيع والجمع لبناء سلسلة نصية جديدة اعتمادًا على أجزاء من السلسلة النصية القديمة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_115" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Zophie a cat'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> newName </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">[</span><span class="lit">0</span><span class="pun">:</span><span class="lit">7</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'the'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> name</span><span class="pun">[</span><span class="lit">8</span><span class="pun">:</span><span class="lit">12</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> name
</span><span class="str">'Zophie a cat'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> newName
</span><span class="str">'Zophie the cat'</span></pre>

<p>
	استعملنا <code>[0:7]</code> و <code>[8:12]</code> للإشارة إلى المحارف التي لا نريد تعديلها، لاحظ أن السلسلة النصية الأصلية <code>'Zophie a cat'</code> لم تعدل، بل أنشأنا سلسلة نصية جديدة.
</p>

<p>
	وصحيحٌ أن القوائم قابلة للتعديل، لكن السطر الثاني في المثال الآتي لن يعدل القائمة <code>eggs</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_117" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggs </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="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggs </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggs
</span><span class="pun">[</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">]</span></pre>

<p>
	لم تبدل القيم في القائمة <code>eggs</code> هنا؛ بل أُنشِئت قائمة جديدة ‎<code>[4, 5, 6]</code>‎ وكتبت فوق القائمة القديمة ‎<code>[1, 2, 3]</code>‎ كما في الشكل الآتي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150682" href="https://academy.hsoub.com/uploads/monthly_2024_06/000037.jpg.819de54f9e8dd0bb4b92f83203332b44.jpg" rel=""><img alt="000037" class="ipsImage ipsImage_thumbnailed" data-fileid="150682" data-unique="yiybyp7tm" src="https://academy.hsoub.com/uploads/monthly_2024_06/000037.jpg.819de54f9e8dd0bb4b92f83203332b44.jpg"> </a>
</p>

<p style="text-align: center;">
	الشكل 2: ما يحدث عند إسناد قائمة جديدة إلى متغير
</p>

<p>
	إذا أردت فعليًا تعديل القائمة الأصلية المخزنة في <code>eggs</code> لتحتوي على <code>‎[4, 5, 6]‎</code>، فعليك فعل شيء يشبه ما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_119" style=""><span class="pun">‎&gt;&gt;&gt;</span><span class="pln"> eggs </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="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">del</span><span class="pln"> eggs</span><span class="pun">[</span><span class="lit">2</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">del</span><span class="pln"> eggs</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">del</span><span class="pln"> eggs</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggs</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="lit">4</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggs</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="lit">5</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggs</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="lit">6</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggs
</span><span class="pun">[</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">]</span></pre>

<p>
	يوضح الشكل الموالي التعديلات السبع التي جرت على القائمة <code>eggs</code> لتصل إلى النتيجة النهائية.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150685" href="https://academy.hsoub.com/uploads/monthly_2024_06/000128.jpg.281a5b59d78fe66111b3fa34f07cf2c8.jpg" rel=""><img alt="000128" class="ipsImage ipsImage_thumbnailed" data-fileid="150685" data-unique="1gir0xwap" src="https://academy.hsoub.com/uploads/monthly_2024_06/000128.jpg.281a5b59d78fe66111b3fa34f07cf2c8.jpg"> </a>
</p>

<p style="text-align: center;">
	الشكل 3: تُغيِّر العبارة <code>del</code> والتابع <code>append()‎</code> قيمة القائمة مباشرة
</p>

<p>
	تغيير قيمة نوع بيانات قابل للتعديل (مثل استخدام العبارة <code>del</code> والتابع <code>append()‎</code> كما في الثالث السابق) سيؤدي إلى تغيير القيمة في مكانها، وذلك لأن قيمة المتغير لا تبدل إلى قائمة جديدة.
</p>

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

<h2 id="tuples">
	الصفوف Tuples
</h2>

<p>
	يكاد يماثل نوع البيانات tuple القوائم تمامًا، مع استثناء أمرين اثنين: الأول أننا نعرف الصفوف عبر قوسين هلاليين <code>()</code> بدلًا من القوسين المربعين <code>[]</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_124" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggs </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="str">'hello'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">42</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="pun">&gt;&gt;&gt;</span><span class="pln"> eggs</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
</span><span class="str">'hello'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggs</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="pun">(</span><span class="lit">42</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="pun">&gt;&gt;&gt;</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">eggs</span><span class="pun">)</span><span class="pln">
</span><span class="lit">3</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_126" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggs </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="str">'hello'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">42</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="pun">&gt;&gt;&gt;</span><span class="pln"> eggs</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="lit">99</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#5&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    eggs</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="lit">99</span><span class="pln">
</span><span class="typ">TypeError</span><span class="pun">:</span><span class="pln"> </span><span class="str">'tuple'</span><span class="pln"> object does </span><span class="kwd">not</span><span class="pln"> support item assignment</span></pre>

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

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

<p>
	جرب الدالة <code>type()‎</code> في المثال الآتي لترى الفرق الذي يحدثه استخدام الفاصلة بعد القيمة عمليًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_128" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> type</span><span class="pun">((</span><span class="str">'hello'</span><span class="pun">,))</span><span class="pln">
</span><span class="pun">&lt;</span><span class="kwd">class</span><span class="pln"> </span><span class="str">'tuple'</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> type</span><span class="pun">((</span><span class="str">'hello'</span><span class="pun">))</span><span class="pln">
</span><span class="pun">&lt;</span><span class="kwd">class</span><span class="pln"> </span><span class="str">'str'</span><span class="pun">&gt;</span></pre>

<p>
	يمكنك استخدام الصفوف في برنامجك لتقول لمن يقرأه من المبرمجين أنك لا تنوي لهذه السلسلة من القيم أن تتغير؛ أي لو أردت قيمًا متسلسلة مرتبة لا تتغير فاستخدم الصفوف.
</p>

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

<h3 id="listtuple">
	تبديل أنواع التسلسلات باستخدام الدوال list()‎ و tuple()‎
</h3>

<p>
	كما تعيد الدالة <code>str(42)‎</code> القيمة <code>'42'</code> وهو التمثيل النصي للرقم <code>42</code>؛ تعيد الدالتان list()<code>‎</code> و <code>tuple()‎</code> نسخة القائمة والصف من القيم الممررة إليها.
</p>

<p>
	جرب المثال الآتي ولاحظ كيف أن نوع القيمة المعادة مختلف عن نوع القيمة الممررة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_130" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> tuple</span><span class="pun">([</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dog'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">])</span><span class="pln">
</span><span class="pun">(</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dog'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> list</span><span class="pun">((</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dog'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">))</span><span class="pln">
</span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dog'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> list</span><span class="pun">(</span><span class="str">'hello'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="str">'h'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'e'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'l'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'l'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'o'</span><span class="pun">]</span></pre>

<p>
	قد يفيدك تحويل صف إلى قائمة إن احتجت إلى نسخة قابلة للتعديل من قيمة ذاك الصف.
</p>

<h2 id="references">
	المرجعيات References
</h2>

<p>
	كما رأيت سابقًا، «تُخزِّن» المتغيرات قيم السلاسل النصية والأعداد، لكن هذا تبسيط لما تقوم به بايثون فعلًا. فتقنيًا تخزن المتغيرات مرجعيةً أو إشارةً إلى مكان تخزين قيمة المتغير في <a href="https://academy.hsoub.com/apps/operating-systems/%D8%A7%D9%84%D8%B0%D8%A7%D9%83%D8%B1%D8%A9-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-r880/" rel="">ذاكرة الحاسوب</a>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_132" style=""><span class="pun">&gt;&gt;&gt;</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="pun">&gt;&gt;&gt;</span><span class="pln"> cheese </span><span class="pun">=</span><span class="pln"> spam
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="lit">100</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="lit">100</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> cheese
</span><span class="lit">42</span></pre>

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

<p>
	ثم حينما تغيّر قيمة المتغير <code>spam</code> إلى <code>100</code> فأنت تنشِئ قيمةً جديدةً وهي <code>100</code> ثم تخزن مرجعيةً إليها في المتغير <code>spam</code>، وهذا لا يؤثر على القيمة الموجودة في المتغير <code>cheese</code>.
</p>

<p>
	تذكر أن القيم العددية من أنواع البيانات غير القابلة للتعديل، أي أن تغيير قيمة <code>spam</code> سيؤدي إلى تغيير المرجعية التي تشير إليها في الذاكرة. لكن لا تعمل القوائم بهذه الطريقة، وذلك لأن القوائم من أنواع البيانات القابلة للتعديل. هذا المثال يسهِّل فهم الآلية السابقة والفروق بين القوائم وغيرها من <a href="https://academy.hsoub.com/programming/artificial-intelligence/%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-%D9%88%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1872/" rel="">أنواع البيانات</a>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_134" style=""><span class="pun">➊</span><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">0</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">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</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"> cheese </span><span class="pun">=</span><span class="pln"> spam </span><span class="com"># ستنسخ المرجعية وليست القائمة</span><span class="pln">
</span><span class="pun">➌</span><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> cheese</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="str">'Hello!'</span><span class="pln"> </span><span class="com"># وهذا ما يغير قيمة عنصر القائمة</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
   </span><span class="pun">[</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Hello!'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">]</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> cheese </span><span class="com"># يشير المتغير إلى القائمة نفسها</span><span class="pln">
   </span><span class="pun">[</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Hello!'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">]</span></pre>

<p>
	قد يبدو الناتج السابق غريبًا بالنسبة إليك، فأنت تعدل فيه على القائمة <code>cheese</code> لكن التغييرات حدثت على المتغير <code>cheese</code> و <code>spam</code> معًا! عند إنشائك للقائمة ➊ فأنت تخزن مرجعيةً إليها في المتغير <code>spam</code>، وفي السطر التالي ➋ نسخت المرجعية الموجودة في <code>spam</code> إلى <code>cheese</code> وليس القائمة نفسها. وهذا يعني أن القيم المخزنة في المتغيرين <code>spam</code> و <code>cheese</code> تشير إلى القائمة نفسها. لاحظ أن هنالك قائمة واحدة لأن القائمة لم تنسَخ بحد ذاتها بل نُسِخَت المرجعية إليها؛ لذا حينما تعدل أحد عناصر القائمة <code>cheese</code> ➌ فأنت تعدل نفس القائمة التي يُشار إليها عبر المتغير <code>spam</code>.
</p>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150679" href="https://academy.hsoub.com/uploads/monthly_2024_06/000041.jpg.5167e257b52cf71791ba94eac06f9270.jpg" rel=""><img alt="000041" class="ipsImage ipsImage_thumbnailed" data-fileid="150679" data-unique="b1qbhvrop" src="https://academy.hsoub.com/uploads/monthly_2024_06/000041.jpg.5167e257b52cf71791ba94eac06f9270.jpg"> </a>
</p>

<p style="text-align: center;">
	الشكل 4: تخزن مرجعية إلى قائمة في المتغيرات، وليست القائمة نفسها
</p>

<p>
	في الشكل الآتي 5 سننسخ المرجعية الموجودة في <code>spam</code> إلى <code>cheese</code>، لاحظ تخزين قيمة المرجعية في <code>cheese</code> وليس القائمة. لاحظ كيف يشير كلا المتغيرين إلى القائمة نفسها:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150678" href="https://academy.hsoub.com/uploads/monthly_2024_06/000132.jpg.e294ff59934cbcbab28f7672b1fc3d27.jpg" rel=""><img alt="000132" class="ipsImage ipsImage_thumbnailed" data-fileid="150678" data-unique="8dlp7u9jn" src="https://academy.hsoub.com/uploads/monthly_2024_06/000132.jpg.e294ff59934cbcbab28f7672b1fc3d27.jpg"> </a>
</p>

<p style="text-align: center;">
	الشكل 5: إسناد قيمة متغير إلى آخر ينسخ المرجعية وليس القائمة
</p>

<p>
	وحينما تعدل القائمة التي يشير إليها المتغير <code>cheese</code> فأنت تعدل القائمة التي يشير إليها <code>spam</code> أيضًا، لأنهما يشيران إلى القائمة نفسها، يمكنك ملاحظة ذلك في الشكل الموالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150680" href="https://academy.hsoub.com/uploads/monthly_2024_06/000077.jpg.1b76d257cf89d04131cabf365b745cd9.jpg" rel=""><img alt="000077" class="ipsImage ipsImage_thumbnailed" data-fileid="150680" data-unique="nu4l1tt3o" src="https://academy.hsoub.com/uploads/monthly_2024_06/000077.jpg.1b76d257cf89d04131cabf365b745cd9.jpg"> </a>
</p>

<p style="text-align: center;">
	الشكل 6: تغيير عنصر في قائمة يشار إليها من متغيرين مختلفين
</p>

<p>
	صحيحٌ أن بايثون تخزن مرجعيات في المتغيرات، لكن من الشائع أن يقول المطورون أن «المتغيرات تحتوي على قيم» وليس «المتغيرات تحتوي على مرجعيات تشير إلى قيم».
</p>

<h3 id="id">
	المعرفات والدالة id()‎
</h3>

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

<p>
	يمكننا استخدام الدالة <code>()id</code> لفهم ذلك، فكل القيم في بايثون لها معرف خاص بها يمكن الحصول عليه باستخدام الدالة <code>id()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_137" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> id</span><span class="pun">(</span><span class="str">'Howdy'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># ستختلف القيمة المعادة في حاسوبك</span><span class="pln">
</span><span class="lit">44491136</span></pre>

<p>
	عندما تشغل بايثون العبارة البرمجية <code>id('Howdy')‎</code> فهي تنشِئ السلسلة النصية <code>'Howdy'</code> في ذاكرة حاسوبك، ويعاد عنوان الذاكرة الرقمي الذي خُزِّنَت السلسلة النصية فيه عبر الدالة id()<code>‎</code>، وتختار بايثون العنوان اعتمادًا على أي بايتات تتوافر في ذاكرة حاسوبك في وقت التنفيذ، لذا ستختلف القيمة في كل مرة تشغل فيها الشيفرة.
</p>

<p>
	وككل السلاسل النصية، السلسلة <code>'Howdy'</code> غير قابلة للتعديل، وإذا حاولت «تعديل» قيمة السلسلة النصية الموجودة في متغير، فستُنشَأ سلسلة نصية جديدة في مكان آخر في الذاكرة ثم سيشير المتغير إلى السلسلة النصية الجديدة. جرب المثال الآتي ولاحظ تغيير المعرف الذي يشير إليه المتغير <code>olive</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_139" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> olive </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Hello'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> id</span><span class="pun">(</span><span class="pln">olive</span><span class="pun">)</span><span class="pln">
</span><span class="lit">44491136</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> olive </span><span class="pun">+=</span><span class="pln"> </span><span class="str">' world!'</span><span class="pln"> </span><span class="com"># سلسلة نصية جديدة</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> id</span><span class="pun">(</span><span class="pln">olive</span><span class="pun">)</span><span class="pln"> </span><span class="com"># يشير المتغير إلى سلسلة نصية مختلفة</span><span class="pln">
</span><span class="lit">44609712</span></pre>

<p>
	لكن يمكن تعديل القوائم لأنها من أنواع البيانات القابلة للتعديل. فالتابع append()<code>‎</code> لا ينشِئ قائمة جديدة حين تنفيذه، بل يعدل القائمة الموجودة، ونسمي هذا السلوك «بالتعديل في المكان» in-place:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_141" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggs </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dog'</span><span class="pun">]</span><span class="pln"> </span><span class="com"># إنشاء قائمة جديدة</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> id</span><span class="pun">(</span><span class="pln">eggs</span><span class="pun">)</span><span class="pln">
</span><span class="lit">35152584</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggs</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="str">'moose'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># يضيف التابع القيم مباشرة</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> id</span><span class="pun">(</span><span class="pln">eggs</span><span class="pun">)</span><span class="pln"> </span><span class="com"># يشير المتغير إلى نفس القائمة السابقة</span><span class="pln">
</span><span class="lit">35152584</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggs </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'bat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cow'</span><span class="pun">]</span><span class="pln"> </span><span class="com"># إنشاء قائمة جديدة لها معرف مختلف</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> id</span><span class="pun">(</span><span class="pln">eggs</span><span class="pun">)</span><span class="pln"> </span><span class="com"># يشير المتغير إلى قائمة مختلفة كليًا</span><span class="pln">
</span><span class="lit">44409800</span></pre>

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

<p>
	التوابع <code>append()‎</code> و <code>extend()‎</code> و <code>remove()‎</code> و <code>sort()‎</code> و <code>reverse()‎</code> وغيرها من توابع القوائم ستعمل القوائم في مكانها. جامع القمامة التلقائي في Python (أي Garbage Collector) يحذف أي قيم لا يشار إليها من المتغيرات لكي يُفرِّغ الذاكرة، وهذا رائع لأن الإدارة اليدوية للذاكرة في لغات البرمجة الأخرى هي سبب رئيسي للعلل البرمجية.
</p>

<h3 id="-9">
	تمرير المرجعيات
</h3>

<p>
	من المهم فهم المرجعيات لاستيعاب كيف تمرر الوسائط إلى الدوال.
</p>

<p>
	حين استدعاء دالة ما، فإن القيم الممررة كوسائط arguments تنسخ إلى المعاملات parameters، وبالنسبة إلى القوائم (والقواميس التي سنتعرف عليها في المقال القادم) هذا يعني أن المرجعية التي تشير إلى القائمة ستنسخ من الوسيط إلى المعامل، ولكي تعي آثار ذلك جرب المثال الآتي باسم <code>passingReference.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_143" style=""><span class="kwd">def</span><span class="pln"> eggs</span><span class="pun">(</span><span class="pln">someParameter</span><span class="pun">):</span><span class="pln">
    someParameter</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="str">'Hello'</span><span class="pun">)</span><span class="pln">

spam </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="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">]</span><span class="pln">
eggs</span><span class="pun">(</span><span class="pln">spam</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></pre>

<p>
	لاحظ أنه حين استدعاء <code>eggs()‎</code> فلن تستعمل القيمة المعادة من الدالة لإسناد قيمة جديدة إلى المتغير <code>spam</code>، بل ستعدل المتغير <code>spam</code> في مكانه مباشرةً؛ وسيخرج الناتج الآتي:
</p>

<pre class="ipsCode">[1, 2, 3, 'Hello']
</pre>

<p>
	وصحيحٌ أن قيمة <code>spam</code> نسخت إلى someParameter لكن ما نسخ فعليًا هو المرجعية إلى نفس القائمة، ولهذا سيؤدي استدعاء التابع <code>append('Hello')‎</code> إلى تعديل القائمة خارج الدالة.
</p>

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

<h3 id="copydeepcopycopy">
	الدالة copy()‎ و deepcopy()‎ في الوحدة copy
</h3>

<p>
	صحيحٌ أن تمرير المرجعيات للإشارة إلى القوائم والقواميس يسهل التعامل معها، لكن إن كانت لدينا دالة تغير القائمة أو القاموس الممرر إليها وكنّا لا نريد إجراء تلك التعديلات على القائمة أو القاموس الأصليين، فحينها يمكننا الاستفادة من الوحدة التي توفرها بايثون باسم <code>copy</code> التي توفر الدالتين <code>copy()‎</code> و <code>deepcopy()‎</code>. أول دالة منهما <code>copy.copy()‎</code> تنشِئ نسخةً طبق الأصل من قيمة قابلة للتعديل كقوائم أو القواميس:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_145" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> copy
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'A'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'B'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'C'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'D'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> id</span><span class="pun">(</span><span class="pln">spam</span><span class="pun">)</span><span class="pln">
</span><span class="lit">44684232</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> cheese </span><span class="pun">=</span><span class="pln"> copy</span><span class="pun">.</span><span class="pln">copy</span><span class="pun">(</span><span class="pln">spam</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> id</span><span class="pun">(</span><span class="pln">cheese</span><span class="pun">)</span><span class="pln"> </span><span class="com"># قائمة مختلفة بمعرف مختلف</span><span class="pln">
</span><span class="lit">44685832</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> cheese</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="lit">42</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="pun">[</span><span class="str">'A'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'B'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'C'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'D'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> cheese
</span><span class="pun">[</span><span class="str">'A'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">42</span><span class="pun">,</span><span class="pln"> </span><span class="str">'C'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'D'</span><span class="pun">]</span></pre>

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

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150677" href="https://academy.hsoub.com/uploads/monthly_2024_06/000025.jpg.2987645aac44f0c60d9a8ef6a3f01685.jpg" rel=""><img alt="000025" class="ipsImage ipsImage_thumbnailed" data-fileid="150677" data-unique="wg21lb9ei" src="https://academy.hsoub.com/uploads/monthly_2024_06/000025.jpg.2987645aac44f0c60d9a8ef6a3f01685.jpg"> </a>
</p>

<p style="text-align: center;">
	الشكل 7: نسخ القائمة عبر <code>copy()‎</code> ينشِئ قائمة جديدة يمكن تعديلها بشكل مستقل عن القائمة الأصلية
</p>

<p>
	إذا كانت لديك قائمة ترغب بنسخ محتوياتها أيضًا فاستعمال الدالة <code>copy.deepcopy()‎</code> بدلًا من <code>copy.copy()‎</code>. ستنسخ الدالة <code>deepcopy()‎</code> القوائم الداخلية أيضًا.
</p>

<h2 id="-10">
	برنامج قصير: لعبة الحياة
</h2>

<p>
	لعبة الحياة لكونواي Conway’s Game of Life هي مثال عن خلايا ذاتية السلوك cellular automata: مجموعة من القوائم التي تحكم سلوك حقل مؤلف من خلايا منفصلة. عمليًا هذه طريقة لإنشاء أشكال متحركة جميلة، يمكنك أن ترسل كل خطوة على ورقة رسم بياني، وتمثل المربعات في ورقة الرسم الخلايا.
</p>

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

<p>
	يمكنك النظر إلى تمثيل لتقدم أجيل لعبة الحياة في الشكل الآتي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150684" href="https://academy.hsoub.com/uploads/monthly_2024_06/000117.jpg.e30916fae8e5aa679784d3c67273a70f.jpg" rel=""><img alt="000117" class="ipsImage ipsImage_thumbnailed" data-fileid="150684" data-unique="cdhrfo1aa" src="https://academy.hsoub.com/uploads/monthly_2024_06/000117.jpg.e30916fae8e5aa679784d3c67273a70f.jpg"> </a>
</p>

<p style="text-align: center;">
	الشكل 8: أربع خطوات أو أجيال في لعبة الحياة
</p>

<p>
	صحيح أن القواعد بسيطة نسبيًا، لكن قد تحدث بعض السلوكيات المثيرة، فيمكن أن تتحرك الأنماط في لعبة الحياة أو أن تتكاثر، أو حتى تحاكي عمل <a href="https://academy.hsoub.com/apps/operating-systems/%D9%88%D8%AD%D8%AF%D8%A9-%D8%A7%D9%84%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%A7%D9%84%D9%85%D8%B1%D9%83%D8%B2%D9%8A%D8%A9-r879/" rel="">المعالجات المركزية CPUs</a>. لكن في أساس كل هذه الأنماط المعقدة برنامج بسيط.
</p>

<p>
	يمكننا استخدام قائمة تحتوي على قوائم داخلها لتمثيل الحقل ثنائي الأبعاد، وتمثل القوائم الداخلية عمودًا من المربعات، وتخزن القيمة '#' للخلايا الحية، والقيمة <code>' '</code> للخلايا الميتة.
</p>

<p>
	اكتب المثال الآتي في ملف باسم <code>conway.py</code>، ولا مشكلة إن لم تفهم كل ما هو مذكور فيه، كل ما عليك هو إدخاله ومحاولة فهم التعليقات والشروحات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_147" style=""><span class="com"># لعبة الحياة</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> random</span><span class="pun">,</span><span class="pln"> time</span><span class="pun">,</span><span class="pln"> copy
WIDTH </span><span class="pun">=</span><span class="pln"> </span><span class="lit">60</span><span class="pln">
HEIGHT </span><span class="pun">=</span><span class="pln"> </span><span class="lit">20</span><span class="pln">

</span><span class="com"># إنشاء قوائم الخلايا</span><span class="pln">
nextCells </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"> x </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="pln">WIDTH</span><span class="pun">):</span><span class="pln">
    column </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">for</span><span class="pln"> y </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="pln">HEIGHT</span><span class="pun">):</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">randint</span><span class="pun">(</span><span class="lit">0</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="lit">0</span><span class="pun">:</span><span class="pln">
            column</span><span class="pun">.</span><span class="pln">append</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">else</span><span class="pun">:</span><span class="pln">
            column</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="str">' '</span><span class="pun">)</span><span class="pln"> </span><span class="com"># إضافة خلية ميتة</span><span class="pln">
    nextCells</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">column</span><span class="pun">)</span><span class="pln"> </span><span class="com"># nextCells هي قائمة تتألف من قوائم للأعمدة</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"> </span><span class="com"># حلقة البرنامج الرئيسية</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'\n\n\n\n\n'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># فصل الخطوة أو الجيل القادم بأسطر فارغة</span><span class="pln">
    currentCells </span><span class="pun">=</span><span class="pln"> copy</span><span class="pun">.</span><span class="pln">deepcopy</span><span class="pun">(</span><span class="pln">nextCells</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"> y </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="pln">HEIGHT</span><span class="pun">):</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> x </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="pln">WIDTH</span><span class="pun">):</span><span class="pln">
            </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">currentCells</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"> end</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">print</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="kwd">for</span><span class="pln"> x </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="pln">WIDTH</span><span class="pun">):</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> y </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="pln">HEIGHT</span><span class="pun">):</span><span class="pln">
            </span><span class="com"># الوصول إلى إحداثيات الخلايا المجاورة</span><span class="pln">
            </span><span class="com"># `% WIDTH` يضمن أن leftCoord سيكون بين 0 و WIDTH - 1</span><span class="pln">
            leftCoord  </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="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> WIDTH
            rightCoord </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="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> WIDTH
            aboveCoord </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">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> HEIGHT
            belowCoord </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">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> HEIGHT

            </span><span class="com"># إحصاء عدد الخلايا المجاورة</span><span class="pln">
            numNeighbors </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> currentCells</span><span class="pun">[</span><span class="pln">leftCoord</span><span class="pun">][</span><span class="pln">aboveCoord</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">
                numNeighbors </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="com"># الخلية في الركن العلوي الأيسر حية</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> currentCells</span><span class="pun">[</span><span class="pln">x</span><span class="pun">][</span><span class="pln">aboveCoord</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">
                numNeighbors </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="com"># الخلية في الأعلى حية</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> currentCells</span><span class="pun">[</span><span class="pln">rightCoord</span><span class="pun">][</span><span class="pln">aboveCoord</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">
                numNeighbors </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="com"># الخلية في الركن العلوي الأيمن حية</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> currentCells</span><span class="pun">[</span><span class="pln">leftCoord</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="str">'#'</span><span class="pun">:</span><span class="pln">
                numNeighbors </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="com"># الخلية على اليسار حية</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> currentCells</span><span class="pun">[</span><span class="pln">rightCoord</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="str">'#'</span><span class="pun">:</span><span class="pln">
                numNeighbors </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="com">#الخلية على اليمين حية</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> currentCells</span><span class="pun">[</span><span class="pln">leftCoord</span><span class="pun">][</span><span class="pln">belowCoord</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">
                numNeighbors </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="com"># الخلية في الركن السفلي الأيسر حية</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> currentCells</span><span class="pun">[</span><span class="pln">x</span><span class="pun">][</span><span class="pln">belowCoord</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">
                numNeighbors </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="com"># الخلية في الأسفل حية</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> currentCells</span><span class="pun">[</span><span class="pln">rightCoord</span><span class="pun">][</span><span class="pln">belowCoord</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">
                numNeighbors </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="com">#  الخلية في الركن السفلي الأيمن حية</span><span class="pln">

            </span><span class="com"># ضبط قيمة القيمة اعتمادًا على قواعد لعبة الحياة</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> currentCells</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="str">'#'</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(</span><span class="pln">numNeighbors </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">or</span><span class="pln">
numNeighbors </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pun">):</span><span class="pln">
                </span><span class="com"># الخلايا التي لها خلايا جارة حية عددها 2 أو 3</span><span class="pln">
                nextCells</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="str">'#'</span><span class="pln">
            </span><span class="kwd">elif</span><span class="pln"> currentCells</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="str">' '</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> numNeighbors </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pun">:</span><span class="pln">
                </span><span class="com"># الخلايا الميتة التي لها 3 خلايا جارة حية</span><span class="pln">
                nextCells</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="str">'#'</span><span class="pln">
            </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
                </span><span class="com"># كل ما بقي يكون ميتًا أو سيمين</span><span class="pln">
                nextCells</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="str">' '</span><span class="pln">
    time</span><span class="pun">.</span><span class="pln">sleep</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="com"># التوقف لمدة ثانية لتجنب تأثير الوموض المزعج</span></pre>

<p>
	لنلقي نظرةً على الشيفرة سطرًا بسطر بدءًا من الأعلى:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_149" style=""><span class="com"># لعبة الحياة</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> random</span><span class="pun">,</span><span class="pln"> time</span><span class="pun">,</span><span class="pln"> copy
WIDTH </span><span class="pun">=</span><span class="pln"> </span><span class="lit">60</span><span class="pln">
HEIGHT </span><span class="pun">=</span><span class="pln"> </span><span class="lit">20</span></pre>

<p>
	استوردنا بدايةً الوحدات التي تحتوي على الدوال التي سنحتاج إليها، تحديدًا الدوال <code>random.randint()‎</code> و <code>time.sleep()‎</code> و <code>copy.deepcopy()‎</code>.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_151" style=""><span class="com"># إنشاء قوائم الخلايا</span><span class="pln">
nextCells </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"> x </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="pln">WIDTH</span><span class="pun">):</span><span class="pln">
    column </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">for</span><span class="pln"> y </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="pln">HEIGHT</span><span class="pun">):</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">randint</span><span class="pun">(</span><span class="lit">0</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="lit">0</span><span class="pun">:</span><span class="pln">
            column</span><span class="pun">.</span><span class="pln">append</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">else</span><span class="pun">:</span><span class="pln">
            column</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="str">' '</span><span class="pun">)</span><span class="pln"> </span><span class="com"># إضافة خلية ميتة</span><span class="pln">
    nextCells</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">column</span><span class="pun">)</span><span class="pln"> </span><span class="com"># nextCells هي قائمة تتألف من قوائم للأعمدة</span></pre>

<p>
	أول خطوة من إنشاء خلايا ذاتية السلوك هي خطوة (أو «جيل») عشوائية تمامًا. سنحتاج إلى إنشاء قائمة تضم قوائم لتخزين السلاسل النصية '#' و <code>' '</code> التي تمثل الخلايا الحية والميتة، وسيدل مكانها في قائمة القوائم على مكانها في الشاشة، فكل قائمة داخلية تمثل عمودًا من الخلايا، واستدعاؤنا للدالة random.randint(0, 1)<code>‎</code> سيعطي الخلية احتمال 50% أن تكون حية و 50% أن تكون ميتة.
</p>

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

<p>
	ستبدأ إحداثيات محور السينات X من 0 في الأعلى وستزداد نحو اليمين، بينما ستبدأ إحداثيات محور العينات Y من 0 أيضًا في الأعلى وستزداد نحو الأسفل، أي أن <code>nextCells[0][0]‎</code> ستمثل الخلية في الركن العلوي الأيسر من الشاشة، بينما <code>nextCells[1][0]‎</code> ستمثل الخلية التي على يمينها، و <code>nextCells[0][1]‎</code> ستمثل الخلية التي تدنوها.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_153" style=""><span class="kwd">while</span><span class="pln"> </span><span class="kwd">True</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="str">'\n\n\n\n\n'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># فصل الخطوة أو الجيل القادم بأسطر فارغة</span><span class="pln">
    currentCells </span><span class="pun">=</span><span class="pln"> copy</span><span class="pun">.</span><span class="pln">deepcopy</span><span class="pun">(</span><span class="pln">nextCells</span><span class="pun">)</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_155" style=""><span class="pln">    </span><span class="com"># طباعة الخلايا الحالية على الشاشة</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> y </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="pln">HEIGHT</span><span class="pun">):</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> x </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="pln">WIDTH</span><span class="pun">):</span><span class="pln">
            </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">currentCells</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"> end</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">print</span><span class="pun">()</span><span class="pln"> </span><span class="com"># طباعة سطر جديد في نهاية السطر</span></pre>

<p>
	حلقات for المتشعبة تعني أننا سنطبع سطرًا كاملًا من الخلايا على الشاشة، ثم يكون متبوعًا بسطر فارغ، ثم نكرر العملية لكل سطر في <code>nextCells</code>.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_157" style=""><span class="pln">    </span><span class="com"># حساب الخطوة أو الجيل القادم اعتمادًا على القيم الحالية للخلايا</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> x </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="pln">WIDTH</span><span class="pun">):</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> y </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="pln">HEIGHT</span><span class="pun">):</span><span class="pln">
            </span><span class="com"># الوصول إلى إحداثيات الخلايا المجاورة</span><span class="pln">
            </span><span class="com"># `% WIDTH` يضمن أن leftCoord سيكون بين 0 و WIDTH - 1</span><span class="pln">
            leftCoord  </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="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> WIDTH
            rightCoord </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="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> WIDTH
            aboveCoord </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">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> HEIGHT
            belowCoord </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">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> HEIGHT</span></pre>

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

<p>
	عامل باقي القسمة <code>%</code> يجري عملية «التفاف للسطر»، فالجار الأيسر لخلية موجودة في العمود الأيسر سيكون <code>‎0 - 1</code> أو <code>‎-1</code>، والالتفاف العمود إلى فهرس العمود الأيمن 59 فسنحسب ‎(0 - 1) % WIDTH، ولأن قيمة WIDTH هي 60 فستكون نتيجة التعبير هي 59. يمكن فعل المثل بالنسبة إلى الخلايا الجارة التي تعلو وتدنو وعلى يمين الخلية الحالية.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_159" style=""><span class="pln">            </span><span class="com"># إحصاء عدد الخلايا المجاورة</span><span class="pln">
            numNeighbors </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> currentCells</span><span class="pun">[</span><span class="pln">leftCoord</span><span class="pun">][</span><span class="pln">aboveCoord</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">
                numNeighbors </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="com"># الخلية في الركن العلوي الأيسر حية</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> currentCells</span><span class="pun">[</span><span class="pln">x</span><span class="pun">][</span><span class="pln">aboveCoord</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">
                numNeighbors </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="com"># الخلية في الأعلى حية</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> currentCells</span><span class="pun">[</span><span class="pln">rightCoord</span><span class="pun">][</span><span class="pln">aboveCoord</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">
                numNeighbors </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="com"># الخلية في الركن العلوي الأيمن حية</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> currentCells</span><span class="pun">[</span><span class="pln">leftCoord</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="str">'#'</span><span class="pun">:</span><span class="pln">
                numNeighbors </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="com"># الخلية على اليسار حية</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> currentCells</span><span class="pun">[</span><span class="pln">rightCoord</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="str">'#'</span><span class="pun">:</span><span class="pln">
                numNeighbors </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="com">#الخلية على اليمين حية</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> currentCells</span><span class="pun">[</span><span class="pln">leftCoord</span><span class="pun">][</span><span class="pln">belowCoord</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">
                numNeighbors </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="com"># الخلية في الركن السفلي الأيسر حية</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> currentCells</span><span class="pun">[</span><span class="pln">x</span><span class="pun">][</span><span class="pln">belowCoord</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">
                numNeighbors </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="com"># الخلية في الأسفل حية</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> currentCells</span><span class="pun">[</span><span class="pln">rightCoord</span><span class="pun">][</span><span class="pln">belowCoord</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">
                numNeighbors </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="com">#  الخلية في الركن السفلي الأيمن حية</span></pre>

<p>
	لتقرير إن كانت الخلية الموجودة في <code>nextCells[x][y]‎</code> ستكون حيةً أو ميتةً فنحتاج إلى إحصاء عدد الخلايا الحية المجاورة للخلية <code>currentCells[x][y]‎</code>، والسلسلة السابقة من تعابير <code>if</code> الشرطية تتحقق من الجارات الثمانية المجاورة للخلية، وتضيف القيمة 1 للمتغير <code>numNeighbors</code> لكل خلية حية.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_161" style=""><span class="pln">            </span><span class="com"># ضبط قيمة القيمة اعتمادًا على قواعد لعبة الحياة</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> currentCells</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="str">'#'</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(</span><span class="pln">numNeighbors </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">or</span><span class="pln">
numNeighbors </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pun">):</span><span class="pln">
                </span><span class="com"># الخلايا التي لها خلايا جارة حية عددها 2 أو 3</span><span class="pln">
                nextCells</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="str">'#'</span><span class="pln">
            </span><span class="kwd">elif</span><span class="pln"> currentCells</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="str">' '</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> numNeighbors </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pun">:</span><span class="pln">
                </span><span class="com"># الخلايا الميتة التي لها 3 خلايا جارة حية</span><span class="pln">
                nextCells</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="str">'#'</span><span class="pln">
            </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
                </span><span class="com"># كل ما بقي يكون ميتًا أو سيمين</span><span class="pln">
                nextCells</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="str">' '</span><span class="pln">
    time</span><span class="pun">.</span><span class="pln">sleep</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="com"># التوقف لمدة ثانية لتجنب تأثير الوموض المزعج</span></pre>

<p>
	ثم بمعرفتنا لعدد الخلايا الجارة الحية للخلية <code>currentCells[x][y]‎</code>، فيمكننا ضبط قيمة <code>nextCells[x][y]‎</code> إلى <code>'#'</code> أو <code>' '</code>. وبعد المرور على جميع إحداثيات x و y فسيتوقف التنفيذ لبرهة باستدعاء <code>time.sleep(1)‎</code> ثم سيكمل تنفيذ البرنامج في بداية حلقة التكرار مجددًا.
</p>

<p>
	هنالك عدد من الأنماط للخلايا لها أسماء مثل «الطائرة الشراعية» أو «الطائرة ذات المروحة» أو «سفينة الفضاء الثقيلة». نمط «الطائرة الشراعية» هو النمط الذي رأيته في الشكل 8 وهو «يتحرك» قطريًا كل أربع خطوات. يمكنك إنشاء «طائرة شراعية» بتبديل السطر الآتي في برنامج <code>conway.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_163" style=""><span class="pln">        </span><span class="kwd">if</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">randint</span><span class="pun">(</span><span class="lit">0</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="lit">0</span><span class="pun">:</span></pre>

<p>
	إلى هذا السطر:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_165" style=""><span class="pln">        </span><span class="kwd">if</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="pun">)</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">((</span><span class="lit">1</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="lit">2</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="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</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="lit">2</span><span class="pun">),</span><span class="pln"> </span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)):</span></pre>

<h2 id="-11">
	الخلاصة
</h2>

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

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

<p>
	يمكن إعادة كتابة قيمة متغير يحتوي على سلسلة نصية أو صف بقيمة أخرى، لكن هذا لا يكافئ تعديل قيمة السلسلة النصية أو الصف في مكانها، مثلما تفعل التوابع <code>append()‎</code> أو <code>remove()‎</code> على القوائم.
</p>

<p>
	لا تخزن المتغيرات قيم القوائم مباشرةً فيها، بل هي تشير إلى تلك القوائم، ومن المهم استيعاب هذه النقطة حين نسخ المتغيرات أو تمرير القوائم كوسائط إلى الدوال. ولأن القيمة التي ستنسخ هي مرجعية إلى القائمة وليست القائمة نفسها، فأي تعديل يجرى على القائمة سيؤثر عليها في كامل البرنامج؛ لكننا نستطيع استخدام الدالة <code>copy()‎</code> أو <code>deepcopy()‎</code> لنسخ القوائم ثم إجراء تعديلات عليها لا تؤثر على القائمة الأصلية.
</p>

<h2 id="-13">
	مشاريع تدريبية
</h2>

<p>
	لكي تتدرب، اكتب برامج لتنفيذ المهام الآتية.
</p>

<h3 id="-14">
	افصل بفاصلة
</h3>

<p>
	لنقل لدينا القائمة الآتية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_167" style=""><span class="pln">spam </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'apples'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bananas'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'tofu'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cats'</span><span class="pun">]</span></pre>

<p>
	اكتب دالة تأخذ قائمةً كمعامل وتعيد سلسلةً نصيةً فيها كل عناصر تلك القائمة مفصولٌ بينها بفاصلة ثم فراغ، وأضف الكلمة and قبل آخر عنصر. فلو كانت لدينا القائمة السابقة فستعيد الدالة القيمة <code>'apples, bananas, tofu, and cats'</code>؛ لكن يجب أن تعمل دالتك مع جميع القيم. تذكر أن تجرب الدالة على قائمة فارغة <code>[]</code>.
</p>

<h3 id="-15">
	سلسلة رمي القطع النقدية
</h3>

<p>
	سنجري تجربة بسيطة. إذا رمينا قطعة نقدية مئة مرة، وكتبنا الحرف H لكل رأس والحرف T لكل نقش، فسيكون لدينا قائمة تشبه T T T T H H H H T T.
</p>

<p>
	إذا طلبنا من كائن بشري (أهلًا بك أخي البشري <span class="ipsEmoji">?</span> ) أن يكتب عشوائيًا نتائج مئة رمية لقطعة نقد، فستحصل على شيء يشبه H T H T H H T H T T والذي يبدو عشوائيًا إذا نظر كائن بشري إليه، لكنه لا يمثل سلسلة عشوائية رياضيًا. فلن يكتب الكائن البشري سلسلة من ستة رؤوس أو ستة نقوش متتالية، مع أن ذلك ممكن رياضيًا لو كانت عملية رمي القطع النقدية عشوائيًا فعليًا. فمن المتوقع أن تكون التوقعات العشوائية للكائنات البشرية تعيسةً (آسف أخي البشري، لكنها الحقيقة <span class="ipsEmoji">?</span> ).
</p>

<p>
	اكتب برنامجًا يعرف كم مرة ظهرت سلسلة من ستة رؤوس أو ستة نقوش في قائمة مولدة عشوائيًا.
</p>

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

<p>
	أجرِ هذه التجربة 10,000 مرة لكي يكون تعرف النسبة التي تحتوي فيها قائمة الرؤوس والنقوش على ستة رؤوس متتالية أو ستة نقوش متتالية. أذكرك أن الدالة <code>random.randint(0, 1)‎</code> ستعيد القيمة <code>0</code> بنسبة 50% والقيمة 1 بنسبة 50%.
</p>

<p>
	يمكنك أن تستفيد من القالب الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_169" style=""><span class="kwd">import</span><span class="pln"> random
numberOfStreaks </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> experimentNumber </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">10000</span><span class="pun">):</span><span class="pln">
    </span><span class="com"># الشيفرة التي ستولد قائمة من 100 قيمة عشوائية لعملية رمي القطعة النقدية</span><span class="pln">

    </span><span class="com"># الشيفرة التي ستتحقق من ظهور 6 رؤوس أو 6 نقوش متتالية</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Chance of streak: %s%%'</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">numberOfStreaks </span><span class="pun">/</span><span class="pln"> </span><span class="lit">100</span><span class="pun">))</span></pre>

<p>
	تذكر أن الرقم الناتج تقريبي عملي، لكن حجم العينة (عشرة آلاف) مناسب؛ لكن إذا كنت تعرف بعض المبادئ الأساسية في الاحتمالات والإحصاء الرياضي فستعرف الإجابة الدقيقة دون الحاجة إلى كتابة البرنامج السابق، لكن من الشائع أن تكون معرفة المبرمجين بالرياضيات تعيسة (على عكس المتوقع).
</p>

<h3 id="-16">
	صورة حرفية
</h3>

<p>
	لنقل أن لدينا قائمة تضم قوائم أخرى، وكل قيمة في القوائم الداخلية هي حرف واحد كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5983_172" style=""><span class="pln">grid </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[[</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="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="pun">],</span><span class="pln">
        </span><span class="pun">[</span><span class="str">'.'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</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="pun">],</span><span class="pln">
        </span><span class="pun">[</span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</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="pun">[</span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'.'</span><span class="pun">],</span><span class="pln">
        </span><span class="pun">[</span><span class="str">'.'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">],</span><span class="pln">
        </span><span class="pun">[</span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'.'</span><span class="pun">],</span><span class="pln">
        </span><span class="pun">[</span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</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="pun">[</span><span class="str">'.'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'O'</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="pun">],</span><span class="pln">
        </span><span class="pun">[</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="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="pun">]]</span></pre>

<p>
	تخيل أن العنصر <code>grid[x][y]‎</code> هو المحرف الموجود في الإحداثيات x و y «للصورة» التي سنرسمها عبر الأحرف. مبدأ الإحداثيات <code>(0, 0)</code> هو الركن العلوي الأيسر، وستزداد إحداثيات x بالذهاب نحو اليمين، وإحداثيات y نحو الأسفل.
</p>

<p>
	انسخ الشبكة السابقة واكتب شيفرة لطباعة الشكل الآتي منها:
</p>

<pre class="ipsCode">..OO.OO..
.OOOOOOO.
.OOOOOOO.
..OOOOO..
...OOO...
....O....
</pre>

<p>
	تلميحة: ستحتاج إلى حلقة تكرار داخل حلقة تكرار، لكي تطبع <code>grid[0][0]‎</code> ثم grid[1][0]<code>‎</code> ثم <code>grid[2][0]‎</code> وهلم جرًا إلى أن تصل إلى <code>grid[8][0]‎</code>؛ ثم ستنتهي من أول صف وتطبع سطرًا جديدًا، ثم تطبع grid[0][1]<code>‎</code> ثم <code>grid[1][1]‎</code> ثم grid[2][1]<code>‎</code> …إلخ. وآخر عنصر سيطبعه برنامجك هو <code>grid[8][5]‎</code>.
</p>

<p>
	تذكر أن تمرر الوسيط المسمى <code>end</code> إلى الدالة <code>print()‎</code> إذا لم تكن تريد طباعة سطر جديد بعد كل استدعاء للدالة <code>print()‎</code>.
</p>

<p>
	ترجمة -بتصرف- للفصل <a href="https://automatetheboringstuff.com/2e/chapter4/" rel="external nofollow">LISTS</a> من كتاب <a href="https://automatetheboringstuff.com/#toc" rel="external nofollow">Automate the Boring Stuff with Python</a>.
</p>

<h2 id="-17">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2336/" rel="">الدوال في لغة بايثون Python</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/python/%D8%A8%D9%86%D9%89-%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2335/" rel="">بنى التحكم في لغة بايثون Python</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/artificial-intelligence/%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-%D9%88%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1872/" rel="">أنواع البيانات والعمليات الأساسية في لغة بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/python/" rel="">تعلم لغة بايثون</a>
	</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>
</ul>
]]></description><guid isPermaLink="false">2339</guid><pubDate>Mon, 03 Jun 2024 16:07:05 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62F;&#x648;&#x627;&#x644; &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646; Python</title><link>https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2336/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_05/---(1).png.9c5226f639a073ef619c9793dd5b15f6.png" /></p>
<p>
	تعرفت في المقالات السابقة على الدوال print()‎ و input()‎ و len()‎، وأصبحت تعرف بتوفير بايثون عدّة دوال مضمنة في اللغة built-in functions مثلها، لكنك تستطيع كتابة دوال خاصة بك أيضًا.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_6" style=""><span class="pun">➊</span><span class="pln"> </span><span class="kwd">def</span><span class="pln"> hello</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="str">'Howdy!'</span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Howdy!!!'</span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hello there.'</span><span class="pun">)</span><span class="pln">

</span><span class="pun">➌</span><span class="pln"> hello</span><span class="pun">()</span><span class="pln">
   hello</span><span class="pun">()</span><span class="pln">
   hello</span><span class="pun">()</span></pre>

<p>
	أول سطر هو عبارة <code>def</code> التي تعرف دالةً باسم hello()‎، والشيفرة التي تلي عبارة <code>def</code> هي جسم الدالة ➋، الذي يحتوي على الشيفرة التي ستنفذ حين استدعاء call الدالة، وليس حين تعريف الدالة.
</p>

<p>
	الأسطر الثلاثة التي تحتوي على hello()‎ ➌ هي استدعاءات الدالة، وعملية استدعاء الدالة هي كتابة اسمها متبوعًا بقوسين، وقد تمرر إليها بعض الوسائط arguments بين القوسين.
</p>

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

<p>
	ولأننا استدعينا الدالة hello()‎ ثلاث مرات، فإن الشيفرة الموجودة داخل الدالة hello()‎ ستنفذ ثلاث مرات، وحينما تشغِّل البرنامج السابق سيظهر لديك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_8" style=""><span class="typ">Howdy</span><span class="pun">!</span><span class="pln">
</span><span class="typ">Howdy</span><span class="pun">!!!</span><span class="pln">
</span><span class="typ">Hello</span><span class="pln"> there</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Howdy</span><span class="pun">!</span><span class="pln">
</span><span class="typ">Howdy</span><span class="pun">!!!</span><span class="pln">
</span><span class="typ">Hello</span><span class="pln"> there</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Howdy</span><span class="pun">!</span><span class="pln">
</span><span class="typ">Howdy</span><span class="pun">!!!</span><span class="pln">
</span><span class="typ">Hello</span><span class="pln"> there</span><span class="pun">.</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_10" style=""><span class="kwd">print</span><span class="pun">(</span><span class="str">'Howdy!'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Howdy!!!'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hello there.'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Howdy!'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Howdy!!!'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hello there.'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Howdy!'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Howdy!!!'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hello there.'</span><span class="pun">)</span></pre>

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

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

<h2 id="def">
	عبارة def مع معاملات
</h2>

<p>
	تذكر حينما كنت تستدعي الدالة print()‎ أو len()‎ كنت تمرر إليها قيمًا تسمى بالوسائط arguments، وذلك بكتابتها بين القوسين. يمكنك أيضًا أن تعرف دوالك التي تقبل وسائط، وجرب هذا المثال في ملف باسم <code>helloFunc2.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_12" style=""><span class="pun">➊</span><span class="pln"> </span><span class="kwd">def</span><span class="pln"> hello</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">print</span><span class="pun">(</span><span class="str">'Hello, '</span><span class="pln"> </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"> hello</span><span class="pun">(</span><span class="str">'Alice'</span><span class="pun">)</span><span class="pln">
   hello</span><span class="pun">(</span><span class="str">'Bob'</span><span class="pun">)</span></pre>

<p>
	ستبدو المخرجات كما يلي حين تشغيل البرنامج السابق:
</p>

<pre class="ipsCode">Hello, Alice
Hello, Bob
</pre>

<p>
	لاحظ أن تعريفنا للدالة hello()‎ في هذا المثال يحتوي على معامل باسم name ➊. المعاملات parameters هي المتغيرات التي تحتوي على قيمة الوسائط arguments. أي حينما نستدعي دالةً مع وسائط arguments فإن قيمة تلك الوسائط ستكون مخزنة في المعاملات parameters.
</p>

<p>
	حين استدعاء الدالة hello()‎ لأول مرة سنمرر إليها القيمة 'Alice' ➌ وسينتقل التنفيذ إلى داخل الدالة، وستُضبَط قيمة المعامل name إلى القيمة 'Alice' تلقائيًا، ومن ثم ستطبع هذه القيمة باستخدام الدالة print()‎ ➋.
</p>

<p>
	أحد الأمور التي من المهم تذكرها حول المعاملات هي أن القيمة المخزنة فيها ستنسى حين إنتهاء تنفيذ الدالة، فلو كتبت print(name)<code>‎</code> بعد استدعاء <code>hello('Bob')‎</code> في البرنامج السابق، فسيظهر لك الخطأ NameError لعدم وجود متغير باسم name، وذلك لأن برنامجنا سيحذف المتغير name بعد إنتهاء استدعاء الدالة <code>hello('Bob')‎</code> ولذا سنشير في print(name)<code>‎‎</code> إلى المتغير name الذي لن يكون موجودًا.
</p>

<p>
	هذا يشبه كثيرًا كيف تحذف قيمة المتغيرات في برامجنا السابقة من الذاكرة حين انتهاء تنفيذها. وسنتحدث عن سبب حدوث ذلك تفصيلًا لاحقًا في هذا المقال حينما نتتحدث عن النطاق المحلي local scope.
</p>

<h2 id="">
	التعريف والاستدعاء والتمرير والوسائط والمعاملات!
</h2>

<p>
	كثرت علينا المصطلحات الجديدة كالتعريف define والاستدعاء call والتمرير pass والوسائط arguments والمعاملات parameters. لننظر سويةً إلى الشيفرة الآتية لمراجعتها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_14" style=""><span class="pun">➊</span><span class="pln"> </span><span class="kwd">def</span><span class="pln"> sayHello</span><span class="pun">(</span><span class="pln">name</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hello, '</span><span class="pln"> </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"> sayHello</span><span class="pun">(</span><span class="str">'Abdullatif'</span><span class="pun">)</span></pre>

<p>
	تعريف الدالة يعني إنشاءها، وكما في عبارة الإسناد <code>spam = 42</code> التي تنشِئ المتغير <code>spam</code> سنستعمل العبارة <code>def</code> لتعريف الدالة <code>sayHello()‎</code> ➊. السطر الذي فيه <code>sayHello('Abdullatif')‎</code> ➋ يستدعي الدالة التي أنشأناها، مما ينقل تنفيذ البرنامج إلى بداية الشيفرة الموجودة داخل الدالة، وسطر الاستدعاء السابق يمرر السلسلة النصية 'Abdullatif' إلى الدالة، والقيمة التي تمرر إلى الدالة تسمى وسيطًا، وسيُسند الوسيط 'Abdullatif' إلى المتغير المحلي المسمى name، وتسمى المتغيرات التي تحمل قيمة الوسائط الممررة إلى الدالة بالمعاملات.
</p>

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

<h2 id="return">
	القيم المعادة وعبارة return
</h2>

<p>
	عندما تستدعي الدالة len()‎ وتمرر إليها وسيطًا مثل 'Hello' فستكون القيمة الناتجة من الدالة هي الرقم 5، الذي يمثل طول السلسلة النصية التي مررتها إليها. يمكننا القول عمومًا أن الناتج إحدى الدوال يسمى بالقيمة المعادة return value من تلك الدالة.
</p>

<p>
	حينما تنشِئ دالةً باستخدام العبارة <code>def</code> فيمكنك أن تحدد ما هي القيمة المعادة من الدالة باستخدام العبارة <code>return</code>. تتألف عبارة <code>return</code> من:
</p>

<ul>
	<li>
		الكلمة المحجوزة <code>return</code>
	</li>
	<li>
		قيمة أو تعبير برمجي يجب أن تعيدها الدالة
	</li>
</ul>

<p>
	حين استخدام تعبير برمجي مع عبارة <code>return</code> فستكون القيمة المعادة هي ناتج ذاك التعبير. فمثلًا البرنامج الآتي يعرف دالةً تعيد سلسلةً نصيةً مختلفةً اعتمادًا على الرقم المُمرَّر إليها كوسيط. احفظ الشيفرة الآتية في ملف باسم <code>magic8Ball.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_16" style=""><span class="pun">➊</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> random

</span><span class="pun">➋</span><span class="pln"> </span><span class="kwd">def</span><span class="pln"> getAnswer</span><span class="pun">(</span><span class="pln">answerNumber</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"> answerNumber </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">return</span><span class="pln"> </span><span class="str">'It is certain'</span><span class="pln">
       </span><span class="kwd">elif</span><span class="pln"> answerNumber </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
           </span><span class="kwd">return</span><span class="pln"> </span><span class="str">'It is decidedly so'</span><span class="pln">
       </span><span class="kwd">elif</span><span class="pln"> answerNumber </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pun">:</span><span class="pln">
           </span><span class="kwd">return</span><span class="pln"> </span><span class="str">'Yes'</span><span class="pln">
       </span><span class="kwd">elif</span><span class="pln"> answerNumber </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">return</span><span class="pln"> </span><span class="str">'Reply hazy try again'</span><span class="pln">
       </span><span class="kwd">elif</span><span class="pln"> answerNumber </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">return</span><span class="pln"> </span><span class="str">'Ask again later'</span><span class="pln">
       </span><span class="kwd">elif</span><span class="pln"> answerNumber </span><span class="pun">==</span><span class="pln"> </span><span class="lit">6</span><span class="pun">:</span><span class="pln">
           </span><span class="kwd">return</span><span class="pln"> </span><span class="str">'Concentrate and ask again'</span><span class="pln">
       </span><span class="kwd">elif</span><span class="pln"> answerNumber </span><span class="pun">==</span><span class="pln"> </span><span class="lit">7</span><span class="pun">:</span><span class="pln">
           </span><span class="kwd">return</span><span class="pln"> </span><span class="str">'My reply is no'</span><span class="pln">
       </span><span class="kwd">elif</span><span class="pln"> answerNumber </span><span class="pun">==</span><span class="pln"> </span><span class="lit">8</span><span class="pun">:</span><span class="pln">
           </span><span class="kwd">return</span><span class="pln"> </span><span class="str">'Outlook not so good'</span><span class="pln">
       </span><span class="kwd">elif</span><span class="pln"> answerNumber </span><span class="pun">==</span><span class="pln"> </span><span class="lit">9</span><span class="pun">:</span><span class="pln">
           </span><span class="kwd">return</span><span class="pln"> </span><span class="str">'Very doubtful'</span><span class="pln">

</span><span class="pun">➍</span><span class="pln"> r </span><span class="pun">=</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">randint</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pun">)</span><span class="pln">
</span><span class="pun">➎</span><span class="pln"> fortune </span><span class="pun">=</span><span class="pln"> getAnswer</span><span class="pun">(</span><span class="pln">r</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">fortune</span><span class="pun">)</span></pre>

<p>
	حين يبدأ تنفيذ البرنامج السابق فستسورد بايثون الوحدة <code>random</code> ➊، ثم ستعرف الدالة getAnswer()‎ ➋، ولأننا عرفنا الدالة ولم نستدعها فلن تنفذ الشيفرة الموجودة داخلها، بل سينتقل التنفيذ مباشرةً إلى استدعاء الدالة <code>random.randint()‎</code> التي مررنا إليها وسيطين هما 1 و 9 ➍ وسيعاد منها عدد عشوائي بين 1 و 9 (بما في ذلك الرقمين 1 و 9) وتخزن هذه القيمة في المتغير <code>r</code>.
</p>

<p>
	تستدعى الدالة getAnswer()‎ مع تمرير الوسيط r ➎، وينتقل التنفيذ إلى بداية الدالة getAnswer()‎ ➌، وستخزن قيمة الوسيط <code>r</code> في المعامل <code>answerNumber</code>، ثم اعتمادًا على القيمة الموجودة في <code>answerNumber</code> فستعيد الدالة إحدى السلاسل النصية المعرفة مسبقًا، ومن ثم سيعود التنفيذ إلى النقطة التي استدعيت فيها الدالة getAnswer()‎ ➎ وستسند السلسلة النصية المعادة إلى المتغير ذي الاسم fortune، الذي سيمرر بدوره إلى الدالة print()‎ ➏ ويطبع على الشاشة.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_18" style=""><span class="pln">r </span><span class="pun">=</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">randint</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pun">)</span><span class="pln">
fortune </span><span class="pun">=</span><span class="pln"> getAnswer</span><span class="pun">(</span><span class="pln">r</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">fortune</span><span class="pun">)</span></pre>

<p>
	إلى السطر المكافئ:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_20" style=""><span class="kwd">print</span><span class="pun">(</span><span class="pln">getAnswer</span><span class="pun">(</span><span class="pln">random</span><span class="pun">.</span><span class="pln">randint</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pun">)))</span></pre>

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

<h2 id="none">
	القيمة None
</h2>

<p>
	هنالك قيمة في بايثون تسمى None وهي تمثل عدم وجود قيمة. والقيمة <code>None</code> هي القيمة الوحيدة لنوع البيانات NoneType، وقد تسمي لغات البرمجة الأخرى هذه القيمة بالاسم null أو nil أو undefined. وكما في القيم المنطقية <code>True</code> و <code>False</code> فيجب أن نكتب <code>None</code> بحرف N كبير.
</p>

<p>
	يمكن أن تفيد هذه القيمة-التي-ليس-لها-قيمة حين الحاجة إلى استعمال قيمة لا تمثل شيئًا، فإحدى استخدامات <code>None</code> مثلًا هي القيمة المعادة من الدالة print()‎ التي تطبع نصًا على الشاشة، لكنها لا تعيد أي قيمة على عكس دوال أخرى مثل len()‎ أو input()‎، ولأن من المفترض أن يكون هنالك قيمة ناتجة لجميع استدعاءات الدوال في بايثون فاستدعاء print()‎ سيعيد القيمة <code>None</code>. لنجرب السطرين الآتيين في الصدفة التفاعلية لنرى ذلك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_22" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hello!'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Hello</span><span class="pun">!</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">None</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> spam
</span><span class="kwd">True</span></pre>

<p>
	تضيف بايثون العبارة <code>return None</code> وراء الكواليس لأي دالة لا يكون لها عبارة <code>return</code> محددة، وهذا ما يشبه كيف تحتوي حلقات التكرار <code><a href="https://wiki.hsoub.com/Python/while" rel="external">while</a></code> و <code><a href="https://wiki.hsoub.com/Python/for" rel="external">for</a></code> على <a href="https://wiki.hsoub.com/Python/for#.D8.B9.D8.A8.D8.A7.D8.B1.D8.A9_continue" rel="external">عبارة continue</a> ضمنية في نهايتها.
</p>

<p>
	ستعاد القيمة <code>None</code> أيضًا إن استخدام عبارة <code>return</code> دون قيمة، أي كتبت الكلمة المفتاحية <code>return</code> كما هي.
</p>

<h2 id="print">
	وسطاء الكلمات المفتاحية والدالة print()‎
</h2>

<p>
	تعرف أغلبية الوسائط بموضعها حين استدعاء الدالة، فمثلًا الاستدعاء <code>random.randint(1, 10)‎</code> مختلف عن الاستدعاء <code>random.randint(10, 1)‎</code>، فحينما نستدعي الدالة <code>random.randint(1, 10)‎</code> فستعيد لنا رقمًا صحيحًا بين 1 و 10 لأن أول وسيط هو الحد الأدنى من المجال والوسيط الثاني هو الحد الأقصى، بينما يسبب استدعاء <code>random.randint(10, 1)‎</code> خطأً.
</p>

<p>
	لكن بدلًا من تعريف قيم الوسائط عبر موضعها، يمكن أن تعرف وسطاء الكلمات المفتاحية keyword arguments بوضع كلمة مفتاحية قبلها حين استدعاء الدالة، وتستخدم وسطاء الكلمات المفتاحية عادةً للمعاملات الاختيارية optional parameters.
</p>

<p>
	فمثلًا تمتلك الدالة print()‎ معاملين اختياريين هما <code>end</code> و <code>sep</code> لضبط ما الذي سيطبع بعد نهاية طبع الوسائط الممررة إليها وما الذي سيطبع بين تلك الوسائط على التوالي.
</p>

<p>
	إذا شغلنا برنامجًا يحتوي على الشيفرة الآتية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_24" style=""><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hello'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'World'</span><span class="pun">)</span></pre>

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

<pre class="ipsCode">Hello
World
</pre>

<p>
	لاحظ أن السلسلتين النصيتين المطبوعتين مفصولتان بسطر وذلك لأن الدالة print()‎ تضيف تلقائيًا محرف السطر الجديد newline character في نهاية السلسلة النصية التي تمرر إليها كوسيط. إلا أننا نستطيع ضبط قيمة الوسيط <code>end</code> لتغيير محرف السطر الجديد إلى سلسلة نصية مختلفة، فمثلًا إذا كتبت الشيفرة الآتية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_26" style=""><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hello'</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="kwd">print</span><span class="pun">(</span><span class="str">'World'</span><span class="pun">)</span></pre>

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

<pre class="ipsCode">HelloWorld
</pre>

<p>
	سيطبع الناتج في سطر وحيد لعدم وجود محرف السطر الجديد بعد السلسلة النصية 'Hello' لأننا مررنا سلسلة نصية فارغة، وهذا ما يفيدك إن أردت تعطيل الإضافة التلقائية للسطر الجديد في نهاية كل استدعاء للدالة print()‎.
</p>

<p>
	إذا مررت عدة <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> إلى الدالة print()‎ فستفصل الدالة بينها تلقائيًا بفراغ واحد. جرب إدخال السطر الآتي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_28" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'cats'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dogs'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'mice'</span><span class="pun">)</span><span class="pln">
cats dogs mice</span></pre>

<p>
	يمكنك تبديل السلسلة النصية التي تفصل بين الوسائط التي ستطبع باستخدام الوسيط <code>sep</code> وتمرير سلسلة نصية مختلفة إليه، جرّب ذلك في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_30" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'cats'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dogs'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'mice'</span><span class="pun">,</span><span class="pln"> sep</span><span class="pun">=</span><span class="str">','</span><span class="pun">)</span><span class="pln">
cats</span><span class="pun">,</span><span class="pln">dogs</span><span class="pun">,</span><span class="pln">mice</span></pre>

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

<h2 id="callstack">
	مكدس الاستدعاء Call Stack
</h2>

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

<p style="text-align: center;">
	<img alt="22-callstack-معرب.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="150312" data-ratio="14.49" data-unique="91e5s1ah8" width="690" src="https://academy.hsoub.com/uploads/monthly_2024_05/22-callstack-.jpg.b037290ea1526ca9c60e9bf4580c7073.jpg">
</p>

<p style="text-align: center;">
	مكدس القصص في دردشتك.
</p>

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

<p>
	لنفهم ما يحدث بالتفصيل سنجرب المثال الآتي بعد حفظه في ملف باسم <code>abcdCallStack.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_32" style=""><span class="pln">   </span><span class="kwd">def</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="str">'a() starts'</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">➊</span><span class="pln"> b</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">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'a() returns'</span><span class="pun">)</span><span class="pln">

   </span><span class="kwd">def</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="str">'b() starts'</span><span class="pun">)</span><span class="pln">
    </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="str">'b() returns'</span><span class="pun">)</span><span class="pln">

   </span><span class="kwd">def</span><span class="pln"> c</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="str">'c() starts'</span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'c() returns'</span><span class="pun">)</span><span class="pln">

   </span><span class="kwd">def</span><span class="pln"> d</span><span class="pun">():</span><span class="pln">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'d() starts'</span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'d() returns'</span><span class="pun">)</span><span class="pln">

</span><span class="pun">➎</span><span class="pln"> a</span><span class="pun">()</span></pre>

<p>
	سينتج البرنامج ما يلي حين تشغيله:
</p>

<pre class="ipsCode">a() starts
b() starts
c() starts
c() returns
b() returns
d() starts
d() returns
a() returns
</pre>

<p>
	أعرف أن الفقرة الآتية متداخلة، لكن حاول أن تركز معي فيها: حين استدعاء a()‎ ➎ فستستدعي b()‎ ➊ التي بدورها ستستدعي c()‎ ➌. والدالة c()‎ لا تستدعي غيرها بل تعرض العبارة c() starts ➍ و c() returns قبل أن يعود التنفيذ إلى السطر الذي استدعاها في b()‎ ➌.
</p>

<p>
	بعد أن يعود التنفيذ إلى الشيفرة في b()‎ التي استدعت c()‎ فستنتهي الدالة b()‎ وتطبع b() returns ثم يعود التنفيذ إلى السطر الذي استدعى b()‎ في a()‎ ➊.
</p>

<p>
	سيستمر التنفيذ في الدالة a()‎ وستستدعى الدالة d()‎، والتي تشبه الدالة c()‎ في كونها لا تستدعي دالةً غيرها بل تطبع d()‎ starts و d() returns قبل أن تعود إلى السطر الذي استدعاها في a()‎ ثم سيكمل التنفيذ من هناك، وسيطبع آخر سطر من a()‎ العبارة a()‎ returns قبل أن ينتهي تنفيذ الدالة a()‎ ونصل إلى نهاية البرنامج.
</p>

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

<p>
	بعد إعادة استدعاء الدالة فستحذف <a href="https://academy.hsoub.com/python/" rel="">بايثون</a> كائن الإطار من أعلى المكدس وتكمل التنفيذ من السطر المخزن في ذاك الكائن. لاحظ أن كائنات الإطار تضاف وتحذف من أعلى المكدس وليس من أي مكان آخر. يوضح الشكل الموالي حالة مكدس الاستدعاء في البرنامج <code>abcdCallStack.py</code> حين استدعاء والعودة من كل دالة:
</p>

<p style="text-align: center;">
	<img alt="23-abcd-callstack(1).jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="150313" data-ratio="14.49" data-unique="0jdyflsvp" width="690" src="https://academy.hsoub.com/uploads/monthly_2024_05/23-abcd-callstack(1).jpg.ac3b9f9ee79acc855cdcc7774c289cc9.jpg">
</p>

<p>
	كائنات الإطار لمكدس الاستدعاء في كل مرحلة من مراحل تنفيذ البرنامج <code>abcdCallStack.py</code>.
</p>

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

<h2 id="-1">
	المجالات العامة والمحلية
</h2>

<p>
	تكون المعاملات parameters والمتغيرات الموجودة داخل إحدى الدوال ضمن مجال محلي local scope. أما المتغيرات التي تسند قيمتها خارج جميع الدوال تكون موجودة في المجال العام global scope.
</p>

<p>
	وبالتالي يسمى المتغير الموجود في مجال محلي بالمتغير المحلي local variable، بينما يسمى المتغير الموجود في المجال العام بالمتغير العام global variable؛ ويجب أن يكون المتغير عامًا أو محليًا، ولا يمكنه أن يكون كلاهما معًا.
</p>

<p>
	يمكنك تخيل المجالات scopes على أنها حاوية للمتغيرات؛ فحينما ينتهي وجود أحد المجالات المحلية فستحذف جميع المتغيرات الموجودة فيه. لاحظ وجود مجال عام وحيد الذي سينُشَأ حينما يبدأ تنفيذ برنامجك وينتهي بإنتهاء تنفيذه. يمكنك التأكد من حذف المتغيرات في المجال العام بعد إنتهاء تنفيذ البرنامج بتجربة الوصول إلى المتغيرات من برنامج آخر.
</p>

<p>
	يُنشَأ المجال المحلي في كل مرة تستدعى فيها إحدى الدوال. فتكون جميع المتغيرات المسندة ضمن الدالة موجودة في المجال المحلي. وحين إعادة قيمة return من الدالة فسينتهي وجود المجال المحلي وستحذف قيمة تلك المتغيرات؛ ولن يتذكر برنامج قيمة المتغيرات المخزنة من الاستدعاء السابق للدالة. تخزن المتغيرات المحلية أيضًا في كانئات الإطار frame objects في مكدس الاستدعاء call stack.
</p>

<p>
	يهمنا معرفة المجال المستخدم لعدة أسباب:
</p>

<ul>
	<li>
		لا يمكن للشيفرات الموجودة في المجال العام أن تستعمل أي متغيرات محلية
	</li>
	<li>
		لكن يمكن للشيفرات في المجال المحلي الوصول إلى المتغيرات العامة
	</li>
	<li>
		الشيفرة في المجال المحلي لإحدى الدوال لا تستطيع استخدام أي متغيرات موجودة في المجال المحلي لدالة أخرى
	</li>
	<li>
		يمكنك استخدام الاسم نفسه لمتغيرات مختلفة على أن تكون موجودة في مجالات مختلفة. أي يمكن أن يسمى متغير محلي بالاسم spam مثلًا ويكون هنالك متغير عام بالاسم <code>spam</code> أيضًا.
	</li>
</ul>

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

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

<h3 id="-2">
	لا يمكن استخدام المتغيرات المحلية في المجال العام
</h3>

<p>
	أمعن النظر في البرنامج الآتي الذي سيتسبب بخطأ حين محاولة تشغيله:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_34" style=""><span class="kwd">def</span><span class="pln"> spam</span><span class="pun">():</span><span class="pln">
</span><span class="pun">➊</span><span class="pln"> eggs </span><span class="pun">=</span><span class="pln"> </span><span class="lit">31337</span><span class="pln">
spam</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">eggs</span><span class="pun">)</span></pre>

<p>
	إذا جربت هذا البرنامج فسيبدو الناتج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_36" style=""><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"C:/test1.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">eggs</span><span class="pun">)</span><span class="pln">
</span><span class="typ">NameError</span><span class="pun">:</span><span class="pln"> name </span><span class="str">'eggs'</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> defined</span></pre>

<p>
	سيحدث الخطأ بسبب وجود المتغير <code>eggs</code> داخل المجال المحلي المنشأ من الدالة spam()‎ ➊. فبعد انتهاء تنفيذ الدالة spam فسيحذف المجال المحلي ولن يبقى هنالك أي متغير باسم <code>eggs</code>، وحينما يحاول البرنامج تشغيل السطر print(eggs)‎ فستعطيك بايثون خطأً تقول فيه أن المتغير <code>eggs</code> غير معرف، وهذا منطقي إذا فكرت مليًا بالأمر؛ فحينما يكون تنفيذ البرنامج في المجال العام فلا توجد أي مجالات محلية ولن تكون هنالك أي متغيرات محلية، وبالتالي لا يمكننا استخدام سوى المتغيرات العامة في المجال العام.
</p>

<h3 id="-3">
	لا يمكن استخدام المتغيرات المحلية في مجالات محلية أخرى
</h3>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_38" style=""><span class="pln">  </span><span class="kwd">def</span><span class="pln"> spam</span><span class="pun">():</span><span class="pln">
    </span><span class="pun">➊</span><span class="pln"> eggs </span><span class="pun">=</span><span class="pln"> </span><span class="lit">99</span><span class="pln">
    </span><span class="pun">➋</span><span class="pln"> olive</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">eggs</span><span class="pun">)</span><span class="pln">

   </span><span class="kwd">def</span><span class="pln"> olive</span><span class="pun">():</span><span class="pln">
       steak </span><span class="pun">=</span><span class="pln"> </span><span class="lit">101</span><span class="pln">
    </span><span class="pun">➍</span><span class="pln"> eggs </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">

</span><span class="pun">➎</span><span class="pln"> spam</span><span class="pun">()</span></pre>

<p>
	حينما يبدأ تشغيل البرنامج فستستدعى الدالة spam()‎ ➎ وسينشأ مجال محلي، وسيضبط المتغير المحلي <code>eggs</code> ➊ إلى 99، ثم ستستدعى الدالة olive()‎ ➋، ثم سينشأ مجال محلي جديد؛ فمن الممكن أن تكون عدة مجالات محلية موجودة جنبًا إلى جنب. وسنضبط قيمة المتغير المحلي <code>Steak</code> إلى 101، وسننشِئ المتغير المحلي <code>eggs</code> -المختلف كليًا عن المتغير الذي يحمل نفس الاسم في المجال المحلي للدالة spam()‎- ونضبط قيمته إلى 0 ➍. حين إعادة الدالة olive()‎ فسيحذف المجال المحلي المنشأ بسبب استدعائها، بما في ذلك المتغير <code>eggs</code> الخاص بها. وسيكمل تنفيذ البرنامج في الدالة spam()‎ ليطبع لنا قيمة المتغير <code>eggs</code> ➌؛ ولأن المجال المحلي الخاص بالدالة spam()‎ ما يزال موجودًا فستكون قيمة <code>eggs</code> هي 99 كما ضبطناها سابقًا في ذلك المجال.
</p>

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

<h3 id="-4">
	يمكن قراءة المتغيرات العامة من مجال محلي
</h3>

<p>
	أمعن النظر في المثال الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_40" style=""><span class="kwd">def</span><span class="pln"> spam</span><span class="pun">():</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">eggs</span><span class="pun">)</span><span class="pln">
eggs </span><span class="pun">=</span><span class="pln"> </span><span class="lit">42</span><span class="pln">
spam</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">eggs</span><span class="pun">)</span></pre>

<p>
	حينما حاولنا طباعة المتغير <code>eggs</code> ضمن الدالة spam()‎ بحثت بايثون عن متغير أو معامل باسم <code>eggs</code> في الدالة spam()‎ لكنها لم تجد، فحينها ستعدّه إشارةً إلى المتغير العام <code>eggs</code>، ولهذا سيطبع البرنامج السابق القيمة 42 حين تنفيذه.
</p>

<h3 id="-5">
	المتغيرات المحلية والعامة التي تحمل الاسم نفسه
</h3>

<p>
	من المقبول تمامًا من الناحية التقنية في بايثون استخدام نفس الاسم لمتغير في المجال العام وآخر في المجال المحلي؛ لكن لتسهيل مقروئية الشيفرة فحاول تجنب فعل ذلك. لترى ما سيحدث فجرب الشيفرة الآتية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_42" style=""><span class="pln">   </span><span class="kwd">def</span><span class="pln"> spam</span><span class="pun">():</span><span class="pln">
    </span><span class="pun">➊</span><span class="pln"> eggs </span><span class="pun">=</span><span class="pln"> </span><span class="str">'spam local'</span><span class="pln">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">eggs</span><span class="pun">)</span><span class="pln">    </span><span class="com"># 'spam local'</span><span class="pln">

   </span><span class="kwd">def</span><span class="pln"> olive</span><span class="pun">():</span><span class="pln">
    </span><span class="pun">➋</span><span class="pln"> eggs </span><span class="pun">=</span><span class="pln"> </span><span class="str">'olive local'</span><span class="pln">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">eggs</span><span class="pun">)</span><span class="pln">    </span><span class="com"># 'olive local'</span><span class="pln">
       spam</span><span class="pun">()</span><span class="pln">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">eggs</span><span class="pun">)</span><span class="pln">    </span><span class="com"># 'olive local'</span><span class="pln">

</span><span class="pun">➌</span><span class="pln"> eggs </span><span class="pun">=</span><span class="pln"> </span><span class="str">'global'</span><span class="pln">
   olive</span><span class="pun">()</span><span class="pln">
   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">eggs</span><span class="pun">)</span><span class="pln">        </span><span class="com"># 'global'</span></pre>

<p>
	سيظهر الناتج الآتي حينما تجرب تشغيل البرنامج السابق:
</p>

<pre class="ipsCode">olive local
spam local
olive local
global
</pre>

<p>
	هنالك ثلاثة متغيرات مختلفة في البرنامج، لكنها كلها مسماة <code>eggs</code>، وهي كما يلي:
</p>

<ul>
	<li>
		➊ متغير باسم <code>eggs</code> موجود في المجال المحلي للدالة spam()‎.
	</li>
	<li>
		➋ متغير باسم <code>eggs</code> موجود في المجال المحلي للدالة olive()‎.
	</li>
	<li>
		➌ متغير باسم <code>eggs</code> موجود في المجال العام.
	</li>
</ul>

<p>
	ولأن هذه المتغيرات المختلفة لها نفس الاسم فسيكون من العسير تتبع أيها يستعمل الآن؛ لذا تجنب استخدام نفس الاسم لأكثر من متغير.
</p>

<h2 id="global">
	العبارة البرمجية global
</h2>

<p>
	إذا أردت تعديل قيمة متغير عام ضمن دالة، فعليك استخدام العبارة البرمجية <code>global</code>. فإذا كان لديك سطر يشبه <code>global eggs</code> في بداية إحدى الدوال فهذا سيخبر بايثون أن «المتغير <code>eggs</code> في هذه الدالة يشير إلى متغير عام، ولا حاجة إلى إ،شاء متغير محلي بهذا الاسم». فمثلًا جرب الشيفرة الآتية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_44" style=""><span class="kwd">def</span><span class="pln"> spam</span><span class="pun">():</span><span class="pln">
  </span><span class="pun">➊</span><span class="pln"> </span><span class="kwd">global</span><span class="pln"> eggs
  </span><span class="pun">➋</span><span class="pln"> eggs </span><span class="pun">=</span><span class="pln"> </span><span class="str">'spam'</span><span class="pln">

eggs </span><span class="pun">=</span><span class="pln"> </span><span class="str">'global'</span><span class="pln">
spam</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">eggs</span><span class="pun">)</span></pre>

<p>
	استدعاء الدالة print()‎ سيؤدي إلى إظهار الناتج الآتي:
</p>

<pre class="ipsCode">spam
</pre>

<p>
	ولأننا صرحنا أن المتغير <code>eggs</code> هو عام global في بداية الدالة spam()‎ ➊، فحينما نضبط eggs إلى 'spam' ➋ فستجرى عملية الإسناد إلى المتغير <code>eggs</code> العام، ولن ينشأ أي متغير محلي.
</p>

<p>
	هنالك أربع قواعد لمعرفة إن كان المتغير في المجال المحلي أم العام:
</p>

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

<p>
	لتأخذ فكرة أفضل عن هذه القواعد فاكتب البرنامج الآتي في محرر الشيفرات واحفظه وجربه:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_46" style=""><span class="kwd">def</span><span class="pln"> spam</span><span class="pun">():</span><span class="pln">
  </span><span class="pun">➊</span><span class="pln"> </span><span class="kwd">global</span><span class="pln"> eggs
     eggs </span><span class="pun">=</span><span class="pln"> </span><span class="str">'spam'</span><span class="pln"> </span><span class="com"># this is the global</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> olive</span><span class="pun">():</span><span class="pln">
  </span><span class="pun">➋</span><span class="pln"> eggs </span><span class="pun">=</span><span class="pln"> </span><span class="str">'olive'</span><span class="pln"> </span><span class="com"># this is a local</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> </span><span class="typ">Steak</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">eggs</span><span class="pun">)</span><span class="pln"> </span><span class="com"># this is the global</span><span class="pln">

eggs </span><span class="pun">=</span><span class="pln"> </span><span class="lit">42</span><span class="pln"> </span><span class="com"># this is the global</span><span class="pln">
spam</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">eggs</span><span class="pun">)</span></pre>

<p>
	سيكون المتغير <code>eggs</code> في الدالة spam()‎ عامًا لوجود العبارة <code>global</code> في بداية الدالة ➊، وسيكون المتغير <code>eggs</code> محليًا في الدالة olive()‎ لاستعماله في عبارة إسناد في تلك الدالة ➋، وسيكون <code>eggs</code> عامًا في steak()‎ ➌ لعدم استخدامه في عبارة إسناد أو العبارة <code>global</code>. إذا شغلت البرنامج السابق فستكون النتيجة هي:
</p>

<pre class="ipsCode">spam
</pre>

<p>
	كقاعدة عامة: سيكون المتغير في دالةٍ ما إما عامًا أو محليًا، ولا يمكن استخدام متغير محلي في دالة باسم <code>eggs</code> ثم استخدام متغير عام بنفس الاسم لاحقًا في الدالة ذاتها.
</p>

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

	<p data-gramm="false">
		ملاحظة: إذا أردت تعديل قيمة مخزنة في متغير عام ضمن دالة فيجب عليك دومًا استخدام العبارة <code>global</code>.
	</p>
</blockquote>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_48" style=""><span class="pln">   </span><span class="kwd">def</span><span class="pln"> spam</span><span class="pun">():</span><span class="pln">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">eggs</span><span class="pun">)</span><span class="pln"> </span><span class="com"># ERROR!</span><span class="pln">
    </span><span class="pun">➊</span><span class="pln"> eggs </span><span class="pun">=</span><span class="pln"> </span><span class="str">'spam local'</span><span class="pln">

</span><span class="pun">➋</span><span class="pln"> eggs </span><span class="pun">=</span><span class="pln"> </span><span class="str">'global'</span><span class="pln">
   spam</span><span class="pun">()</span></pre>

<p>
	ستظهر رسالة الخطأ الآتية إذا حاولت تجربة البرنامج السابق:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_50" style=""><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"C:/sameNameError.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    spam</span><span class="pun">()</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"C:/sameNameError.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> spam
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">eggs</span><span class="pun">)</span><span class="pln"> </span><span class="com"># ERROR!</span><span class="pln">
</span><span class="typ">UnboundLocalError</span><span class="pun">:</span><span class="pln"> local variable </span><span class="str">'eggs'</span><span class="pln"> referenced before assignment</span></pre>

<p>
	يظهر الخطأ لأن بايثون سترى عبارة إسناد للمتغير <code>eggs</code> ضمن الدالة spam()‎ ➊ وبالتالي ستعد المتغير على أنه محلي، لكننا نحاول طباعة قيمة <code>eggs</code> قبل إسناد أي قيمة له، أي أن المتغير المحلي <code>eggs</code> غير موجود، فسيظهر الخطأ ولن تستعمل بايثون المتغير العام <code>eggs</code> ➋.
</p>

<h3 id="-6">
	تعامل مع الدوال على أنها «صناديق سوداء»
</h3>

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

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

<h2 id="-7">
	التعامل مع الاستثناءات
</h2>

<p>
	حينما يحدث خطأ -أو بتعبير أدق «استثناء» exception- في برنامجك فهذا يعني توقف عملية التنفيذ كلها. ولا تريد أن يحدث ذلك عمليًا في البرامج الحقيقية، وإنما تريد أن يحس برنامجك بوجود الأخطاء ويتعامل معها ثم يكمل تنفيذه بسلام.
</p>

<p>
	فالبرنامج الآتي يتسبب بخطأ القسمة على صفر. جربه:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_52" style=""><span class="kwd">def</span><span class="pln"> spam</span><span class="pun">(</span><span class="pln">divideBy</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">42</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> divideBy

</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">spam</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">spam</span><span class="pun">(</span><span class="lit">12</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="lit">0</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="lit">1</span><span class="pun">))</span></pre>

<p>
	عرفنا الدالة spam()‎ ومررنا إليها وسيطًا بقيم مختلفة وطبعنا قيمة قسمة العدد 42 على القيمة الممررة. هذا هو ناتج تنفيذ الشيفرة السابقة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_54" style=""><span class="lit">21.0</span><span class="pln">
</span><span class="lit">3.5</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"C:/zeroDivide.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</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="lit">0</span><span class="pun">))</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"C:/zeroDivide.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> spam
    </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">42</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> divideBy
</span><span class="typ">ZeroDivisionError</span><span class="pun">:</span><span class="pln"> division by zero</span></pre>

<p>
	يظهر الاستثناء <code>ZeroDivisionError</code> حينما نقسم عددًا على صفر. ويظهر لنا رقم السطر الذي يسبب هذا الاستثناء، وستعرف منه أن العبارة return في الدالة spam()‎ هي من تسبب الخطأ.
</p>

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

<p>
	يمكنك وضع الشيفرة التي قد تسبب بخطأ القسمة على الصفر ضمن كتلة <code>try</code> واستخدام كتلة <code>except</code> للتعامل مع حدوث الخطأ:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_56" style=""><span class="kwd">def</span><span class="pln"> spam</span><span class="pun">(</span><span class="pln">divideBy</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">42</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> divideBy
    </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="str">'Error: Invalid argument.'</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="lit">2</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="lit">12</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="lit">0</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="lit">1</span><span class="pun">))</span></pre>

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

<pre class="ipsCode">21.0
3.5
Error: Invalid argument.
None
42.0
</pre>

<p>
	لاحظ أن أية أخطاء تحدث أثناء استدعاءات الدوال ضمن كتلة <code>try</code> فستعالج أيضًا. جرب البرنامج الآتي التي يستدعي الدالة spam()‎ ضمن كتلة <code>try</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_59" style=""><span class="kwd">def</span><span class="pln"> spam</span><span class="pun">(</span><span class="pln">divideBy</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">42</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> divideBy

</span><span class="kwd">try</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="lit">2</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="lit">12</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="lit">0</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="lit">1</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="str">'Error: Invalid argument.'</span><span class="pun">)</span></pre>

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

<pre class="ipsCode">21.0
3.5
Error: Invalid argument.
</pre>

<p>
	سبب عدم تنفيذ print(spam(1))‎ هو انتقال التنفيذ إلى الشيفرة الموجودة في كتلة <code>except</code> مباشرةً، ولن تعود لإكمال بقية كتلة <code>try</code>، بل ستكمل تنفيذ بقية البرنامج كالمعتاد.
</p>

<h2 id="-8">
	برنامج قصير لرسم زكزاك
</h2>

<p>
	لنستعمل المفاهيم البرمجية التي تعلمناها حتى الآن لإنشاء برنامج حركي بسيط. سينشِئ هذا البرنامج شكل زكزاك إلى أن يوقفه المستخدم بالضغط على زر Stop في محرر Mu أو بالضغط على <code>Ctrl+C</code>. سيبدو ناتج البرنامج بعد تنفيذه كما يلي:
</p>

<pre class="ipsCode">    ********
   ********
  ********
 ********
********
 ********
  ********
   ********
    ********
</pre>

<p>
	اكتب الشيفرة الآتية واحفظها في ملف باسم <code>zigzag.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_61" style=""><span class="kwd">import</span><span class="pln"> time</span><span class="pun">,</span><span class="pln"> sys
indent </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="com"># كم فراغًا نضع كمسافة بادئة</span><span class="pln">
indentIncreasing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">True</span><span class="pln"> </span><span class="com"># هل ستزيد المسافة البادئة أم لا</span><span class="pln">

</span><span class="kwd">try</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"> </span><span class="com"># حلقة تكرار البرنامج الأساسية</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">' '</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> indent</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="kwd">print</span><span class="pun">(</span><span class="str">'********'</span><span class="pun">)</span><span class="pln">
        time</span><span class="pun">.</span><span class="pln">sleep</span><span class="pun">(</span><span class="lit">0.1</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"> indentIncreasing</span><span class="pun">:</span><span class="pln">
            </span><span class="com"># زيادة المسافة البادئة</span><span class="pln">
            indent </span><span class="pun">=</span><span class="pln"> indent </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> indent </span><span class="pun">==</span><span class="pln"> </span><span class="lit">20</span><span class="pun">:</span><span class="pln">
                </span><span class="com"># تغيير الاتجاه</span><span class="pln">
                indentIncreasing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">

        </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
            </span><span class="com"># إنقاص عدد الفراغات</span><span class="pln">
            indent </span><span class="pun">=</span><span class="pln"> indent </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> indent </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"># تغيير الاتجاه</span><span class="pln">
                indentIncreasing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">
</span><span class="kwd">except</span><span class="pln"> </span><span class="typ">KeyboardInterrupt</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>
	لننظر إلى الشيفرة سطرًا بسطر بدءًا من الأعلى.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_63" style=""><span class="kwd">import</span><span class="pln"> time</span><span class="pun">,</span><span class="pln"> sys
indent </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="com"># كم فراغًا نضع كمسافة بادئة</span><span class="pln">
indentIncreasing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">True</span><span class="pln"> </span><span class="com"># هل ستزيد المسافة البادئة أم لا</span></pre>

<p>
	في البداية علينا أن نستورد الوحدتين time و sys، وسيستخدم برنامجنا متغيرين اثنين: المتغير <code>indent</code> الذي يتتبع كم فراغًا يجب أن نضع كمسافة بادئة قبل النجوم الثمانية، و <code>indentIncreasing</code> الذي يحتوي على قيمة <a href="https://wiki.hsoub.com/Python/boolean" rel="external">منطقية بوليانية</a> لتحدد إذا كانت المسافة البادئة ستزيد أم تنقص.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_65" style=""><span class="kwd">try</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"> </span><span class="com"># حلقة تكرار البرنامج الأساسية</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">' '</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> indent</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="kwd">print</span><span class="pun">(</span><span class="str">'********'</span><span class="pun">)</span><span class="pln">
        time</span><span class="pun">.</span><span class="pln">sleep</span><span class="pun">(</span><span class="lit">0.1</span><span class="pun">)</span><span class="pln"> </span><span class="com"># توقف لعُشر ثانية</span></pre>

<p>
	ثم وضعنا بقية البرنامج داخل عبارة <code>try</code>؛ فحينما يضغط المستخدم على Ctrl+C أثناء تشغيل برنامج بايثون فستطلق الاستثناء <code>KeyboardInterrupt</code>، وإذا لم تكن هنالك عبارة <code>try-except</code> لمعالجة الاستثناء فسينهار البرنامج وتظهر رسالة خطأ قبيحة. لتفادي ذلك سنعالج الاستثناء <code>KeyboardInterrupt</code> بأنفسنا باستدعاء الدالة sys.exit()‎ (هذه الشيفرة موجودة بعد نهاية كتلة <code>try</code>).
</p>

<p>
	حلقة التكرار اللانهائية while True:<code>‎</code> ستكرر التعليمات الموجودة في برنامجنا للأبد، واستخدمنا التعبير ‎' ' * indent<code>‎</code> لطباعة العدد الصحيح من المسافات البادئة، لكننا لا نريد أن ننتقل إلى سطر جديد بعد تلك الفراغات فنمرر الوسيط <code>end=''‎</code> إلى الدالة print()‎. الاستدعاء الثاني للدالة print()‎ سيطبع لنا 8 نجوم.
</p>

<p>
	لم نشرح الدالة time.sleep()‎ بعد، لكن يكفي القول أنها توقف تشغيل البرنامج مؤقتًا لعُشر ثانية 0.1.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_67" style=""><span class="pln">        </span><span class="kwd">if</span><span class="pln"> indentIncreasing</span><span class="pun">:</span><span class="pln">
            </span><span class="com"># زيادة المسافة البادئة</span><span class="pln">
            indent </span><span class="pun">=</span><span class="pln"> indent </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> indent </span><span class="pun">==</span><span class="pln"> </span><span class="lit">20</span><span class="pun">:</span><span class="pln">
                </span><span class="com"># تغيير الاتجاه</span><span class="pln">
                indentIncreasing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">False</span></pre>

<p>
	ثم سنعدل مقدار المسافات البادئة للمرة القادمة التي تنفذ فيها حلقة <code>while</code>. فإذا كان <code>indentIncreasing</code> هو <code>True</code> فسنضيف واحد إلى <code>indent</code>. لكن حينما تصل المسافة البادئة إلى 20 فنرغب بتقليل المسافة البادئة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_69" style=""><span class="pln">        </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
            </span><span class="com"># إنقاص عدد الفراغات</span><span class="pln">
            indent </span><span class="pun">=</span><span class="pln"> indent </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> indent </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"># تغيير الاتجاه</span><span class="pln">
                indentIncreasing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">True</span></pre>

<p>
	أما إذا كانت <code>indentIncreasing</code> هي <code>False</code> فسننقص واحد من المتغير <code>indent</code>، وحينما تصل قيمته إلى 0 فسنحتاج إلى زيادة المسافات البادئة مجددًا، وفي كلتا الحالتين سيعود تنفيذ البرنامج إلى بداية حلقة التكرار لطباعة النجوم مجددًا.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_248_71" style=""><span class="kwd">except</span><span class="pln"> </span><span class="typ">KeyboardInterrupt</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>Ctrl+C</code> في أي مرحلة من مراحل تنفيذ حلقة التكرار الموجودة داخل كتلة <code>try</code> فسيطلق الاستثناء <code>KeyboardInterrrupt</code> ثم يعالج في عبارة <code>except</code>، سيستمر تنفيذ البرنامج داخل كتلة <code>expect</code> الذي سيشغل الدالة sys.exit()‎ لإنهاء البرنامج. وعلى الرغم من أن حلقة التكرار لانهائية، لكننا نوفر طريقة آمنة لإنهاء تشغيل التطبيق من المستخدم.
</p>

<h2 id="-9">
	الخلاصة
</h2>

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

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

<p>
	والآن بعد أن تعلمت الدوال في هذا المقال، ما رأيك أن تجرب ما تعلمته في التطبيق العملي الموالي؟ وطبعًا، لا تنسَ مشاركتنا نتائج تطبيقك في التعليقات:
</p>

<p>
	اكتب دالةً باسم collatz()‎ التي تقبل معاملًا واحدًا اسمه <code>number</code>، إذا كان <code>number</code> زوجيًا فستطبع الدالة <code>number // 2</code> ثم تعيد تلك القيمة، وإذا كان العدد <code>number</code> فرديًا فستطبع وتعيد ناتج <code>3 * number + 1</code>.
</p>

<p>
	ثم اكتب برنامجًا يسمح للمستخدم بإدخال رقم صحيح واستمر باستدعاء الدالة collatz()‎ على ذاك الرقم حتى تعيد الدالة القيمة 1. (ستعمل هذه الدالة لجميع الأعداد الصحيحة، وستكون النتيجة دومًا 1! لا يعرف علماء الرياضيات تحديدًا لماذا، لكن برنامجك هو تطبيق عملي على معضلة كولاتز، حتى أن بعضهم يطلق عليها «أبسط معضلة رياضية مستحيلة»).
</p>

<p>
	تذكر أن تحول القيمة المعادة من input()‎ إلى رقم صحيح عبر الدالة int()‎، وإلا فستعدها بايثون على أنها سلسلة نصية.
</p>

<p>
	تلميحة: يكون العدد <code>number</code> زوجيًا إذا كان باقي القسمة على 2 هو 0 أي <code>number % 2 == 0</code> وفرديًا إذا كان <code>number % 2 == 1</code>. يجب أن يبدو شكل تنفيذ البرنامج كما يلي:
</p>

<pre class="ipsCode">Enter number:
3
10
5
16
8
4
2
1
</pre>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://automatetheboringstuff.com/2e/chapter3/" rel="external nofollow">Functions</a> من كتاب <a href="https://automatetheboringstuff.com/#toc" rel="external nofollow">Automate the boring stuff with Python</a> لصاحبه Al Sweigart.
</p>

<h2 id="-10">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/python/%D8%A8%D9%86%D9%89-%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2335/" rel="">بنى التحكم في لغة بايثون Python</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/artificial-intelligence/%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-%D9%88%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1872/" rel="">أنواع البيانات والعمليات الأساسية في لغة بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/python/" rel="">تعلم لغة بايثون</a>
	</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>
</ul>
]]></description><guid isPermaLink="false">2336</guid><pubDate>Wed, 29 May 2024 16:05:01 +0000</pubDate></item><item><title>&#x628;&#x646;&#x649; &#x627;&#x644;&#x62A;&#x62D;&#x643;&#x645; &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646; Python</title><link>https://academy.hsoub.com/programming/python/%D8%A8%D9%86%D9%89-%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2335/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_05/----(1).png.136a3992105efbf3a42874761b346c12.png" /></p>
<p>
	أصبحت تعرف أن هنالك تعليمات وأن البرامج تتألف من سلسلة من التعليمات، لكن قوة البرمجة الحقيقية لا تقع في تنفيذ مجموعة من التعليمات واحدةً تلو الأخرى وكأنك تتبضع قائمة التسوق. فاعتمادًا على نتيجة بعض التعبيرات البرمجية يستطيع البرنامج أن يتخطى تنفيذ مجموعة من التعليمات أو تكررها أو يختار بعضها لتنفيذه.
</p>

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

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

<p style="text-align: center;">
	<img alt="8-rain-flowchartمعرب-.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="150264" data-ratio="78.53" data-unique="15ae0ied2" style="width: 600px; height: auto;" width="694" src="https://academy.hsoub.com/uploads/monthly_2024_05/8-rain-flowchart-.jpg.fb3f9184a8d37a30e81b3da31f9c5490.jpg">
</p>

<p style="text-align: center;">
	مخطط تدفقي يخبرك ما تفعل إن كانت السماء تمطر
</p>

<p>
	من الشائع أن يكون في المخططات التدفقية أكثر من طريق من البداية إلى النهاية، والأمر سيان بالنسبة إلى شيفرات تطبيقات الحاسوب. تُمثَّل نقاط التفرع في المخططات التدفقية باستخدام شكل المعيّن diamond بينما تُمثَّل بقية الخطوات بمستطيلات عادية، وتكون البداية والنهاية على شكل مستطيل بحواف مدورة.
</p>

<p>
	قبل أن تتعلم عن عبارات بنى التحكم، فعليك أن تعرف كيفية تمثيل خيارات «نعم» و «لا»، بعدها ستحتاج إلى فهم كيفية كتابة نقاط التفرع <a href="https://academy.hsoub.com/programming/python/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2325/" rel="">بلغة بايثون</a>؛ ولهذا الغرض سنحتاج إلى تعلم القيم المنطقية أو البوليانية Boolean وعوامل المقارنة والعوامل المنطقية.
</p>

<h2 id="boolean">
	القيم المنطقية Boolean
</h2>

<p>
	يكون <a href="https://academy.hsoub.com/programming/python/%D9%81%D9%87%D9%85-%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-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-r720/" rel="">لأنواع البيانات</a> التي تعلمناها سابقًا من سلاسل نصية وأرقام صحيحة وأرقام ذات فاصلة، عدد لا متناهي من القيم التي يمكن أن تأخذها. لكن <a href="https://wiki.hsoub.com/Python/boolean" rel="external">للقيم المنطقية أو البوليانية</a> تملك نوعين من القيم فقط: <code>True</code> و <code>False</code> (نقول عنها أنها قيم بوليانية Boolean نسبةً إلى العالم الرياضي جورج بولي)، وحين إدخالها في شيفرة بايثون فستلاحظ عدم وجود علامات الاقتباس التي تحيط <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>، وتبدأ دومًا بالحرف الكبير T أو F وتكون بقية الكلمة بأحرف صغيرة.
</p>

<p>
	أدخل ما يلي في الصدفة التفاعلية، لاحظ الأخطاء التي ستظهر لك في بعض التعليمات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_6" style=""><span class="pun">➊</span><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
   </span><span class="kwd">True</span><span class="pln">
</span><span class="pun">➋</span><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> true
   </span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
     </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#2&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
       true
   </span><span class="typ">NameError</span><span class="pun">:</span><span class="pln"> name </span><span class="str">'true'</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> defined
</span><span class="pun">➌</span><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">True</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="lit">2</span><span class="pln">
   </span><span class="typ">SyntaxError</span><span class="pun">:</span><span class="pln"> can</span><span class="str">'t assign to keyword</span></pre>

<p>
	وكأي قيمة أخرى، يمكن للقيم المنطقية أن تستعمل في التعابير البرمجية ويمكن أن تخزن في المتغيرات ➊، وإن لم تستعمل حالة الأحرف الصحيحة ➋ أو جربت استخدام <code>True</code> أو <code>False</code> لأسماء المتغيرات ➌ فستظهر لك رسالة خطأ.
</p>

<h2 id="">
	عوامل المقارنة
</h2>

<p>
	تقارن <a href="https://wiki.hsoub.com/Python/comparisons" rel="external">عوامل المقارنة comparison operators</a> بين قيمتين وتكون النتيجة هي قيمة منطقية بوليانية واحدة، الجدول الآتي يستعرض عوامل المقارنة:
</p>

<table>
	<thead>
		<tr>
			<th>
				العامل
			</th>
			<th>
				المعنى
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				==
			</td>
			<td>
				يساوي
			</td>
		</tr>
		<tr>
			<td>
				!=‎
			</td>
			<td>
				لا يساوي
			</td>
		</tr>
		<tr>
			<td>
				&lt;
			</td>
			<td>
				أصغر
			</td>
		</tr>
		<tr>
			<td>
				&gt;
			</td>
			<td>
				أكبر
			</td>
		</tr>
		<tr>
			<td>
				&lt;=
			</td>
			<td>
				أصغر أو يساوي
			</td>
		</tr>
		<tr>
			<td>
				&gt;=‎
			</td>
			<td>
				أكبر أو يساوي
			</td>
		</tr>
	</tbody>
</table>

<p style="text-align: center;">
	الجدول 2: عوامل المقارنة
</p>

<p>
	تكون نتيجة استخدام هذه العوامل هي <code>True</code> أو <code>False</code> اعتمادًا على القيم التي تعطيها لها. لنجرب الآن بعض تلك العوامل ولنبدأ بالعاملين <code>==</code> و <code>‎!=‎</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_8" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">42</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">42</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">42</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">99</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</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">3</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</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">2</span><span class="pln">
</span><span class="kwd">False</span></pre>

<p>
	وكما قد تتوقع، ستكون نتيجة عامل «يساوي» <code>==</code> هي <code>True</code> حينما تساوت القيمتان على يمينه ويساره، وعامل «لا يساوي» ستكون نتيجته <code>True</code> حينما تختلف القيمتان على يمينه ويساره. يمكننا استخدام العاملين <code>==</code> و ‎!=<code>‎</code> على أي نوع من <a href="https://wiki.hsoub.com/Python#.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_.D9.81.D9.8A_.D9.84.D8.BA.D8.A9_.D8.A8.D8.A7.D9.8A.D8.AB.D9.88.D9.86" rel="external">أنواع البيانات</a>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_10" style=""><span class="pln">  </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'hello'</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">'hello'</span><span class="pln">
   </span><span class="kwd">True</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'hello'</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">'Hello'</span><span class="pln">
   </span><span class="kwd">False</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'dog'</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="str">'cat'</span><span class="pln">
   </span><span class="kwd">True</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">True</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">
   </span><span class="kwd">True</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">True</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">
   </span><span class="kwd">True</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">42</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">42.0</span><span class="pln">
   </span><span class="kwd">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="lit">42</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">'42'</span><span class="pln">
   </span><span class="kwd">False</span></pre>

<p>
	لاحظ أن القيم العددية سواءً كانت <a href="https://wiki.hsoub.com/Python/int" rel="external">صحيحة int</a> أو <a href="https://wiki.hsoub.com/Python/float" rel="external">ذات فاصلة عائمة float</a> لا تتساوي مع القيمة النصية. فالتعبير 42 == '42' ➊ نتيجته هي <code>Flase</code> لأن بايثون تعدّ الرقم 42 مختلفًا عن السلسلة النصية '42'.
</p>

<p>
	أما المعاملات ‎&gt;<code>‎</code> و ‎<code>&lt;</code>‎ و <code>‎</code>&lt;=‎ و ‎&gt;=<code>‎</code> في لا تعمل إلا مع القيم العددية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_12" style=""><span class="pln">   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">42</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">100</span><span class="pln">
   </span><span class="kwd">True</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">42</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">100</span><span class="pln">
   </span><span class="kwd">False</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">42</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">42</span><span class="pln">
   </span><span class="kwd">False</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggCount </span><span class="pun">=</span><span class="pln"> </span><span class="lit">42</span><span class="pln">
</span><span class="pun">➊</span><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggCount </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">42</span><span class="pln">
   </span><span class="kwd">True</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> myAge </span><span class="pun">=</span><span class="pln"> </span><span class="lit">29</span><span class="pln">
</span><span class="pun">➋</span><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> myAge </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
   </span><span class="kwd">True</span></pre>

<h3 id="-1">
	الفرق بين عامل <code>=</code> و <code>==</code>
</h3>

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

<ul>
	<li>
		عامل المساواة <code>==</code> يتأكد إن كانت القيمتان عن يمينه ويساره متساويتين.
	</li>
	<li>
		عامل الإسناد <code>=</code> يضع التي على اليمين في المتغير الذي على اليسار.
	</li>
</ul>

<p>
	قد يساعدك في التذكر أن عامل المساواة <code>==</code> فيه حرفان، مثل معامل عدم المساواة <code>‎!=‎</code> تمامًا.
</p>

<p>
	ستستخدم عوامل المقارنة كثيرًا لمقارنة قيمة أحد المتغيرات مع قيمة أخرى، كما في <code>eggCount &lt;= 42</code> ➊ و <code>myAge &gt;= 10</code> ➋، فلو كنتَ تعرف قيمة المتغير كيف ستكون قبل أن تشغل برنامجك فلا حاجة إلى المقارنة كلها، فليس من المنطقي أن تكتب <code>'dog' != 'cat'</code> في شيفرتك بل تكتب <code>True</code> مباشرةً. سترى أمثلة كثيرة عن ذلك أثناء تعلمك لبنى التحكم.
</p>

<h2 id="-2">
	العوامل المنطقية البوليانية
</h2>

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

<h3 id="-3">
	العوامل المنطقية الثنائية
</h3>

<p>
	يعمل العاملان <code>and</code> و <code>or</code> على قيمتين أو تعبيرين منطقيين، لهذا يسميان بالعوامل المنطقية الثنائية binary Boolean operators. ينتج العامل <code>nad</code> القيمة <code>True</code> إذا كانت كلا القيمتان المنطقيتان تساوي <code>True</code>، وإلا فالنتيجة هي <code>False</code>. أدخل التعابير البرمجية الآتية في الصدفة التفاعلية لترى أثر هذا العامل عمليًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_14" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">True</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">True</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">
</span><span class="kwd">False</span></pre>

<p>
	جداول الحقيقة truth table هو جدول في الجبر المنطقي البولياني يوضح ناتج كل شكل من أشكال التعابير المنطقية. جدول الحقيقة الآتي يوضح ناتج كل عملية ممكنة مع العامل <code>and</code>:
</p>

<table>
	<thead>
		<tr>
			<th>
				التعبير
			</th>
			<th>
				النتيجة
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				True and True
			</td>
			<td>
				True
			</td>
		</tr>
		<tr>
			<td>
				True and False
			</td>
			<td>
				False
			</td>
		</tr>
		<tr>
			<td>
				False and True
			</td>
			<td>
				False
			</td>
		</tr>
		<tr>
			<td>
				False and False
			</td>
			<td>
				False
			</td>
		</tr>
	</tbody>
</table>

<p style="text-align: center;">
	الجدول 2: جدول الحقيقة للعامل <code>and</code>
</p>

<p>
	وفي المقابل تكون نتيجة العامل <code>or</code> هي <code>True</code> إذا كان أحد القيمتين المنطقيتين يساوي <code>True</code>، أما إذا كانت كلتاهما <code>Flase</code> فنتيجة التعبير هي <code>False</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_16" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">False</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">False</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">
</span><span class="kwd">False</span></pre>

<p>
	يمكنك أن تعرف ناتج كل تعبير ممكن مع العامل <code>or</code> من جدول الحقيقة الخاص به.
</p>

<table>
	<thead>
		<tr>
			<th>
				التعبير
			</th>
			<th>
				النتيجة
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				True or True
			</td>
			<td>
				True
			</td>
		</tr>
		<tr>
			<td>
				True or False
			</td>
			<td>
				True
			</td>
		</tr>
		<tr>
			<td>
				False or True
			</td>
			<td>
				True
			</td>
		</tr>
		<tr>
			<td>
				False or False
			</td>
			<td>
				False
			</td>
		</tr>
	</tbody>
</table>

<p style="text-align: center;">
	الجدول 3: جدول الحقيقة للعامل <code>or</code>
</p>

<h3 id="not">
	العامل <code>not</code>
</h3>

<p>
	وعلى النقيض من العاملين <code>and</code> و <code>or</code>، يستخدم العامل <code>not</code> على قيمة أو تعبير منطقي واحد، ولهذا هو عامل أحادي unary operator. ما يفعله العامل <code>not</code> هو عكس القيمة المنطقية الحالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_18" style=""><span class="pln">   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">
   </span><span class="kwd">False</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">not</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">
   </span><span class="kwd">True</span></pre>

<p>
	وكما في نفي النفي في حديثنا العادي، يمكننا أن نجعل العامل <code>not</code> متشعبًا ➊، لكن لا يوجد سبب لفعل ذلك في البرامج العملية. الجدول الآتي هو جدول الحقيقة للعامل <code>not</code>:
</p>

<table>
	<thead>
		<tr>
			<th>
				التعبير
			</th>
			<th>
				النتيجة
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				not True
			</td>
			<td>
				False
			</td>
		</tr>
		<tr>
			<td>
				not False
			</td>
			<td>
				True
			</td>
		</tr>
	</tbody>
</table>

<p style="text-align: center;">
	الجدول 4: جدول الحقيقة للعامل <code>not</code>
</p>

<h2 id="-4">
	المزج بين العوامل المنطقية وعوامل المقارنة
</h2>

<p>
	لما كانت نتيجة استخدام عوامل المقارنة هي قيمة منطقية، فيمكننا استخدامها في تعابير برمجية مع العوامل المنطقية.
</p>

<p>
	تذكر أن العوامل المنطقية <code>and</code> و <code>or</code> و <code>not</code> هي عوامل منطقية لأنها تعمل على القيم المنطقية <code>True</code> و <code>False</code>؛ بينما التعابير التي تحتوي على عوامل مقارنة مثل <code>‎4 &lt; 5</code> ليست قيمًا منطقية بحد ذاتها لكنها تعابير تُنتِج قيمًا منطقية.
</p>

<p>
	جرب إدخال بعض التعابير المنطقية التي فيها عوامل مقارنة في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_20" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="lit">4</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(</span><span class="lit">5</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">6</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="lit">4</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(</span><span class="lit">9</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">6</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</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="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="pun">(</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="pun">)</span><span class="pln">
</span><span class="kwd">True</span></pre>

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

<p>
	يمكنك أن تتخيل أن عملية تقدير قيمة التعبير البرمجي <code>‎(4 &lt; 5) and (5 &lt; 6)‎</code> تشبه ما يلي:
</p>

<p style="text-align: center;">
	<img alt="9-boolean-and-comparison-operators.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="150273" data-ratio="106.90" data-unique="z4g2bvzdi" width="145" src="https://academy.hsoub.com/uploads/monthly_2024_05/9-boolean-and-comparison-operators.jpg.0ec7ab0f54f985100490f65b9650dc5f.jpg">
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_22" style=""><span class="pun">&gt;&gt;&gt;</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">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">not</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">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="kwd">and</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">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="pun">+</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
</span><span class="kwd">True</span></pre>

<p>
	سيكون للعوامل المنطقية ترتيب لتقدير القيمة كما في العوامل الرياضية، فبعد تقدير قيمة العمليات الحسابية وعمليات المقارنة، ستعمل بايثون على عوامل <code>not</code> أولًا، ثم عوامل <code>and</code> ثم عوامل <code>or</code>.
</p>

<h2 id="-5">
	عناصر بنى التحكم
</h2>

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

<h3 id="-6">
	الشروط
</h3>

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

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

<h3 id="-7">
	الكتل البرمجة
</h3>

<p>
	تجمَِع أسطر الشيفرات البرمجية في بايثون على شكل كتل blocks، ويمكنك أن تعرف متى تبدأ الكتلة ومتى تنتهي من المسافة البادئة indent للأسطر البرمجية.
</p>

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

<ul>
	<li>
		تبدأ الكتلة البرمجية حين زيادة المسافة البادئة.
	</li>
	<li>
		يمكن أن تحتوي الكتل البرمجية على كتل أخرى.
	</li>
	<li>
		تنتهي الكتل حينما تقل المسافة البادئة إلى الصفر أو إلى المسافة البادئة للكتلة الأب.
	</li>
</ul>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_24" style=""><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="pun">‘</span><span class="typ">Ahmed</span><span class="pun">’</span><span class="pln">
  password </span><span class="pun">=</span><span class="pln"> </span><span class="str">'swordfish'</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> name </span><span class="pun">==</span><span class="pln"> </span><span class="str">'Ahmed'</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="str">'Hello, Ahmed’)
       if password == '</span><span class="pln">swordfish</span><span class="str">':
        ➋ print('</span><span class="typ">Access</span><span class="pln"> granted</span><span class="pun">.</span><span class="str">')
       else:
        ➌ print('</span><span class="typ">Wrong</span><span class="pln"> password</span><span class="pun">.</span><span class="str">')</span></pre>

<p>
	تبدأ أول كتلة من الشيفرات ➊ في السطر print('Hello, Ahmed’)‎ وتضم إليها جميع الأسطر البرمجية التي تليها، وداخل هذه الكتلة هنالك كتلة أخرى ➋ التي تحتوي سطرًا واحدًا داخلها فيه print('Access granted.')‎، أما الكتلة الثالثة ➌ والأخيرة ففيها print('Wrong password.')‎.
</p>

<h2 id="-8">
	تنفيذ البرنامج
</h2>

<p>
	تبدأ بايثون بتنفيذ مثالنا السابق <code>hello.py</code> من أول البرنامج حتى نهايته سطرًا بسطر، وعملية تنفيذ البرنامج (التي تسمى program execution أو اختصارًا execution) هي اصطلاح يشير إلى التعليمة البرمجية التي يجري تنفيذها حاليًا، فلو كانت شيفرة برنامجك مطبوعةً على ورقة وتشير بإصبعك إلى السطر الذي يجري تنفيذه حاليًا فتشير إصبعك هنا إلى خط سير تنفيذ البرنامج.
</p>

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

<h2 id="-9">
	عبارات بنى التحكم
</h2>

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

<h3 id="if">
	عبارة if
</h3>

<p>
	أكثر نوع شائع من بنى التحكم هو <a href="https://wiki.hsoub.com/Python/if" rel="external">العبارة الشرطية if</a>، ففيها ستُنفَّذ الكتلة البرمجية التي تلي <code>if</code> إذا كان الشرط محققًا أي <code>True</code>، وسيتخطاها البرنامج إن لم يكن الشرط محققًا أي <code>False</code>.
</p>

<p>
	فإذا أردنا أن نقرأ عبارة <code>if</code> البرمجة باللغة العربية فسنقول «إذا كان الشرط محققًا، فنفذ الكتلة البرمجية الآتية».
</p>

<p>
	تتألف عبارة <code>if</code> في بايثون مما يلي:
</p>

<ul>
	<li>
		الكلمة المفتاحية <code>if</code>
	</li>
	<li>
		الشرط، وهو التعبير الذي تكون نتيجته هي <code>True</code> أو <code>False</code>
	</li>
	<li>
		نقطتان رأسيتان <code>:</code>
	</li>
	<li>
		كتلة برمجية تلي ما سبق، تكون فيها الأسطر مسبوقة بمسافة بادئة
	</li>
</ul>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_26" style=""><span class="kwd">if</span><span class="pln"> name </span><span class="pun">==</span><span class="pln"> </span><span class="str">'Ahmed'</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hi, Ahmed.'</span><span class="pun">)</span></pre>

<p>
	تنتهي جميع عبارات بنى التحكم بنقطتين رأسيتين <code>:</code> متبوعة بكتلة برمجية، والكتلة البرمجية في مثالنا هي التي تحتوي على <code>print('Hi, Ahmed.')‎</code>. يوضح الشكل الآتي المخطط التدفقي للشيفرة السابقة:
</p>

<p style="text-align: center;">
	<img alt="10-if-flowchartمعرب.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="150272" data-ratio="90.64" data-unique="4vqmy4kiz" style="width: 400px; height: auto;" width="481" src="https://academy.hsoub.com/uploads/monthly_2024_05/10-if-flowchart.jpg.30f02601718fdd00f0d2cb326b241c53.jpg">
</p>

<h3 id="else">
	عبارات else
</h3>

<p>
	يمكن اختياريًا أن يأتي بعد كتلة <code>if</code> <a href="https://wiki.hsoub.com/Python/for#.D8.B9.D8.A8.D8.A7.D8.B1.D8.AA.D8.A7_break_.D9.88_else" rel="external">العبارة else</a>، وتنفذ كتلة <code>else</code> في حال كان شرط عبارة <code>if</code> غير محقق <code>False</code>. أي بالعربية يمكننا أن نقول «إذا كان الشرط محققًا، فنفذ الكتلة البرمجية الآتية، وإلا فنفذ هذه الكتلة».
</p>

<p>
	لا تملك عبارة <code>else</code> شرطًا، وتتألف <code>else</code> مما يلي:
</p>

<ul>
	<li>
		الكلمة المفتاحية <code>else</code>
	</li>
	<li>
		نقطتان رأسيتان <code>:</code>
	</li>
	<li>
		كتلة برمجية تلي ما سبق، تكون فيها الأسطر مسبوقة بمسافة بادئة
	</li>
</ul>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_28" style=""><span class="kwd">if</span><span class="pln"> name </span><span class="pun">==</span><span class="pln"> </span><span class="str">'Ahmed'</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hi, Ahmed.'</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="str">'Hello, stranger.'</span><span class="pun">)</span></pre>

<p style="text-align: center;">
	<img alt="11-else-flowchart-معرب.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="150270" data-ratio="83.18" data-unique="puepihdee" style="width: 400px; height: auto;" width="547" src="https://academy.hsoub.com/uploads/monthly_2024_05/11-else-flowchart-.jpg.b01616afaf27cc1a03936ac31349e518.jpg">
</p>

<p style="text-align: center;">
	يبين المخطط التدفقي للبرنامج السابق
</p>

<h3 id="elif">
	عبارات elif
</h3>

<p>
	تعرفنا سابقًا على عبارة <code>if</code> و <code>else</code> التي يجب أن تنفذ إحداهما، لكن ماذا لو كنّا نريد وجود أكثر من احتمال أو أكثر من شرط؟ تعمل العبارة <code>elif</code> كأنها «وإلا إذا كان كذا» <code>else if</code>، وتأتي بعد عبارة <code>if</code> أو <code>elif</code> أخرى.
</p>

<p>
	توفر عبارة <code>elif</code> شرطًا بديلًا يمكن التحقق إن كان محققًا إن كانت الشروط التي تسبقه غير محققة.
</p>

<p>
	تتألف عبارة <code>elif</code> في بايثون مما يلي:
</p>

<ul>
	<li>
		الكلمة المفتاحية <code>elif</code>
	</li>
	<li>
		الشرط، وهو التعبير الذي تكون نتيجته هي <code>True</code> أو <code>False</code>
	</li>
	<li>
		نقطتان رأسيتان <code>:</code>
	</li>
	<li>
		كتلة برمجية تلي ما سبق، تكون فيها الأسطر مسبوقة بمسافة بادئة
	</li>
</ul>

<p>
	لنضف عبارة <code>elif</code> إلى برنامجنا الذي نتحقق فيه من اسم المستخدم:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_30" style=""><span class="kwd">if</span><span class="pln"> name </span><span class="pun">==</span><span class="pln"> </span><span class="str">'Ahmed'</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hi, Ahmed.'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">elif</span><span class="pln"> age </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">12</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You are not Ahmed, kiddo.'</span><span class="pun">)</span></pre>

<p>
	سنتحقق هذه المرة من عمر المستخدم، فإن كان عمره أقل من 12 فسيقول له «أنت لست أحمد يا غلام!». يمكننا تمثيل البرنامج بمخطط التدفق الآتي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150271" href="https://academy.hsoub.com/uploads/monthly_2024_05/12-elif-flowchart-.jpg.ea2aa4dd28cb7aae3a40b3c7b42cd400.jpg" rel=""><img alt="12-elif-flowchart-معرب.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="150271" data-ratio="100.00" data-unique="faovn2fpk" style="width: 400px; height: auto;" width="600" src="https://academy.hsoub.com/uploads/monthly_2024_05/12-elif-flowchart-.thumb.jpg.571d71e6c995ba1a41c9e21c4b465c48.jpg"></a>
</p>

<p style="text-align: center;">
	مخطط التدفق للعبارة <code>elif</code>
</p>

<p>
	ستفَّذ الكتلة البرمجية التي تلي <code>elif</code> إن كان عمر المستخدم <code>age &lt; 12</code> وكان الشرط <code>name == 'Ahmed'‎</code> غير محقق <code>False</code>. لكن إن كان كلا الشرطين غير محقق فسيتجاوز البرنامج تنفيذ الكتلتين البرمجيتين، وليس من الضروري أي ينفذ أحد الكتل البرمجية، فقد تنفذ عبارة واحدة أو لا تنفذ أي عبارة.
</p>

<p>
	بعد أن يتحقق شرط إحدى العبارات الشرطية فسيتجاوز البرنامج بقية عبارات <code>elif</code> كلها. فعلى سبيل المثال أنشِئ الملف <code>vampire.py</code> وضع فيه الشيفرة الآتية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_32" style=""><span class="pln">age </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3000</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> name </span><span class="pun">==</span><span class="pln"> </span><span class="typ">Ahmed</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hi, Ahmed.'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">elif</span><span class="pln"> age </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">12</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You are not Ahmed, kiddo.'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">elif</span><span class="pln"> age </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">2000</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Unlike you, Ahmed is not an vampire.'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">elif</span><span class="pln"> age </span><span class="pun">&gt;</span><span class="pln"> </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="str">'You are not Ahmed, grannie.'</span><span class="pun">)</span></pre>

<p>
	أضفنا هنا عبارتَي <code>elif</code> لبرنامج الترحيب بالمستخدم، وأضفنا جوابين مختلفين بناءً على العمر age. يظهر المخطط التدفقي الآتي سير عمل البرنامج:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150266" href="https://academy.hsoub.com/uploads/monthly_2024_05/13-multiple-elif-flowchart-.jpg.f40f0494696b90f779b2208d118ed81a.jpg" rel=""><img alt="13-multiple-elif-flowchart-معرب.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="150266" data-ratio="155.04" data-unique="wneye7ove" width="387" src="https://academy.hsoub.com/uploads/monthly_2024_05/13-multiple-elif-flowchart-.thumb.jpg.df32f6cf2627e98da364e3f19b553518.jpg"></a>
</p>

<p style="text-align: center;">
	المخطط التدفقي لعبارات <code>elif</code> متعددة في برنامج <code>vampire.py</code>.
</p>

<p>
	لترتيب عبارات <code>elif</code> أهمية، ولتجربة أهمية ترتيبها فلنحاول إضافة علّة لبرنامجنا. تذكر أن البرنامج سيتخطى عبارات <code>elif</code> بعد تحقيق شرط إحداها، لذا إذا غيرنا ترتيب الشيفرة إلى ما يلي وحفظناه باسم <code>vampire2.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_34" style=""><span class="pln">   name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Abdullatif'</span><span class="pln">
   age </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3000</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> name </span><span class="pun">==</span><span class="pln"> </span><span class="str">'Ahmed'</span><span class="pun">:</span><span class="pln">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hi, Ahmed.'</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">elif</span><span class="pln"> age </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">12</span><span class="pun">:</span><span class="pln">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You are not Ahmed, kiddo.'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">➊</span><span class="pln"> </span><span class="kwd">elif</span><span class="pln"> age </span><span class="pun">&gt;</span><span class="pln"> </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="str">'You are not Ahmed, grannie.'</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">elif</span><span class="pln"> age </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">2000</span><span class="pun">:</span><span class="pln">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Unlike you, Ahmed is not an undead, vampire.'</span><span class="pun">)</span></pre>

<p>
	إذا جربنا البرنامج وكانت قيمة المتغير <code>age</code> تساوي 3000 مثلًا، فقد تتوقع أن برنامج سيطبع العبارة التي تقول أن عمره أكثر من 2000 سنة، لكن ولمّا كانت الشرط <code>age &gt; 100</code> محققًا <code>True</code> (وذلك لأن 3000 أكبر من 100 بالفعل) ➊، فستعرض عبارة الترحيب بالعجوز وستخطى تنفيذ البرنامج جميع عبارات <code>elif</code> الأخرى. لذا من المهم الانتباه إلى ترتيب عبارات <code>elif</code>.
</p>

<p>
	المخطط التدفقي الآتي يظهر سير تنفيذ الشيفرة السابقة. لاحظ كيف جرى تبديل المعين الذي يحتوي على age &gt; 100 و age &gt; 2000.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150265" href="https://academy.hsoub.com/uploads/monthly_2024_05/14-bug-flowchart-.jpg.3383e540849d7f03176d915f54dcd179.jpg" rel=""><img alt="14-bug-flowchart-معرب.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="150265" data-ratio="155.44" data-unique="qkoeebloc" width="386" src="https://academy.hsoub.com/uploads/monthly_2024_05/14-bug-flowchart-.thumb.jpg.60743b21623969cd71e6bb3e63827950.jpg"></a>
</p>

<p style="text-align: center;">
	المخطط التدفقي لتنفيذ برنامج <code>vampire2.py</code>، لاحظ أن الفرع الذي عليه إشارة × لا ينفذ أبدًا، لكنه إذا كان العمر age أكبر من 2000 فهو بكل تأكيد أكبر من 100 أيضًا.
</p>

<p>
	يمكنك أن تضع عبارة <code>else</code> بعد آخر عبارة <code>elif</code> اختياريًا، وفي هذه الحالة سنضمن تنفيذ كتلة برمجية واحدة فقط لا غير، أي في حال كانت جميع شروط <code>if</code> و <code>elif</code> هي <code>False</code> فستنفَّذ كتلة <code>else</code>. لنعد كتابة مثال الترحيب بالمستخدم لنستعمل فيه <code>if</code> و <code>elif</code> و <code>else</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_36" style=""><span class="pln">name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Abdullatif'</span><span class="pln">
age </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3000</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> name </span><span class="pun">==</span><span class="pln"> </span><span class="str">'Ahmed'</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hi, Ahmed.'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">elif</span><span class="pln"> age </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">12</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You are not Ahmed, kiddo.'</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="str">'You are neither Ahmed nor a little kid.'</span><span class="pun">)</span></pre>

<p>
	يظهر الشكل الآتي المخطط التدفقي للمثال السابق، الذي سنسميه <code>littleKid.py</code>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150263" href="https://academy.hsoub.com/uploads/monthly_2024_05/15-if-elif-else-flowchart-.jpg.32a8720cc33df34af7fe90b186a5c38b.jpg" rel=""><img alt="15-if-elif-else-flowchart-معرب.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="150263" data-ratio="119.05" data-unique="e432wad0e" style="width: 400px; height: auto;" width="504" src="https://academy.hsoub.com/uploads/monthly_2024_05/15-if-elif-else-flowchart-.thumb.jpg.713f3713863fe3bb4b1f21107930f1f6.jpg"></a>
</p>

<p style="text-align: center;">
	المخطط التدفقي لبرنامج <code>liitleKid.py</code>.
</p>

<p>
	يمكننا وصف هذا النمط من بنى التحكم باللغة العربية: «إذا كان أول شرط محققًا فافعل كذا، وإلا إن كان الشرط الثاني محققًا فافعل كذا، وإلا فافعل كذا». من المهم أن تنتبه إلى ترتيب عبارات <code>if</code> و<code>elif</code> و <code>else</code> حين استخدامها لكي تتجنب العلل المنطقية في برامجك. وتذكر أن هنالك عبارة <code>if</code> وحيدة فقط لا غير، وأي عبارات <code>elif</code> يجب أن تأتي بعدها؛ وإذا أردت ضمان تنفيذ إحدى الكتل البرمجية فأنهِ بنى التحكم بعبارة <code>else</code>.
</p>

<h3 id="while">
	حلقة التكرار while
</h3>

<p>
	يمكنك أن تعيد تنفيذ إحدى الكتل البرمجية مرارًا وتكرارًا باستخدام <a href="https://wiki.hsoub.com/Python/while" rel="external">عبارة while</a>. وستُنفَّذ الشيفرة الموجودة في الكتلة التي تلي شرط <code>while</code> طالما كان الشرط محققًا <code>True</code>.
</p>

<p>
	تتألف عبارة <code>while</code> في بايثون مما يلي:
</p>

<ul>
	<li>
		الكلمة المفتاحية <code>while</code>
	</li>
	<li>
		الشرط، وهو التعبير الذي تكون نتيجته هي <code>True</code> أو <code>False</code>
	</li>
	<li>
		نقطتان رأسيتان <code>:</code>
	</li>
	<li>
		كتلة برمجية تلي ما سبق، تكون فيها الأسطر مسبوقة بمسافة بادئة
	</li>
</ul>

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

<p>
	للنظر إلى الفرق بين العبارة الشرطية <code>if</code> وحلقة <code>while</code> لهما نفس الشرط وتفعلان نفس الفعل في الكتلة التي تليهما. هذه هي الشيفرة التي نستعمل العبارة الشرطية <code>if</code> فيها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_38" style=""><span class="pln">spam </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> spam </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hello, world.'</span><span class="pun">)</span><span class="pln">
    spam </span><span class="pun">=</span><span class="pln"> spam </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span></pre>

<p>
	وهذه هي الشيفرة التي نستعمل الحلقة <code>while</code> فيها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_40" style=""><span class="pln">spam </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"> spam </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hello, world.'</span><span class="pun">)</span><span class="pln">
    spam </span><span class="pun">=</span><span class="pln"> spam </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span></pre>

<p>
	تشبه هذه التعابير بعضها بعضًا، إذ تتحقق <code>if</code> و <code>while</code> من أن قيمة المتغير <code>spam</code> أصغر من 5، ثم تعرض رسالةً ترحيبيةً وتزيد قيمة المتغير <code>spam</code> بمقدار 1.
</p>

<p>
	لكن حينما تشغل البرنامجين السابقين فستجد نتيجةً مختلفةً لكلٍ منهما، ففي البرنامج الذي فيه if سترى عبارة الترحيب مرة واحدة، بينما تكرر العبارة الترحيبية 5 مرات في برنامج while! لننظر إلى المخططين التدفقيين للبرنامجين السابقين في الشكلين المواليين لنفهم ما حدث:
</p>

<p style="text-align: center;">
	<img alt="16-if-while-flowchart.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="150274" data-ratio="92.01" data-unique="408ppr5g7" style="width: 400px; height: auto;" width="551" src="https://academy.hsoub.com/uploads/monthly_2024_05/16-if-while-flowchart.jpg.75759565a79e5b23e4ecc4ad0e330b04.jpg">
</p>

<p style="text-align: center;">
	المخطط التدفقي للبرنامج الذي يحتوي على العبارة الشرطية <code>if</code>.
</p>

<p style="text-align: center;">
	<img alt="17-if-while-flowchart.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="150275" data-ratio="92.20" data-unique="ea55tp2ae" style="width: 400px; height: auto;" width="551" src="https://academy.hsoub.com/uploads/monthly_2024_05/17-if-while-flowchart.jpg.bec4a14a692d865bd5456e9f2e24c7f5.jpg">
</p>

<p style="text-align: center;">
	المخطط التدفقي للبرنامج الذي يحتوي على العبارة الشرطية <code>while</code>.
</p>

<p>
	تتحقق العبارة الشرطية <code>if</code> من الشرط وتطبع "Hello, World" مرةً واحدةً بعد تحقق الشرط، ثم ينتهي تنفيذ البرنامج. بينما البرنامج الذي فيه حلقة <code>while</code> فسينفذ 5 مرات لأن قيمة العدد <code>spam</code> تزيد مرة في نهاية كل حلقة تكرار، وهذا يعني أن الحلقة ستنفذ 5 مرات قبل أن يصبح الشرط <code>spam &lt; 5</code> غير محقق <code>False</code>.
</p>

<p>
	ستجري عملية التحقق من شرط حلقة <code>while</code> في بداية كل دورة iteration، أي في بداية كل تنفيذ لحلقة <code>while</code>؛ وإذا كان الشرط محققًا <code>True</code> فستنفذ الكتلة، ثم بعد ذلك يعاد التحقق من الشرط مجددًا. لاحظ أنه إذا كان شرط حلقة <code>while</code> غير محقق <code>False</code> من أول مرة فلن تنفَّذ الحلقة أبدًا وسيتخطاها البرنامج.
</p>

<h4 id="while-1">
	حلقة while المزعجة
</h4>

<p>
	هذا برنامج بسيط يطلب منك باستمرار أن تدخل "your name" في سطر الأوامر حين سؤاله عن اسمك.
</p>

<p>
	أنشِئ ملفًا جديدًا من File ثم New وأدخل الشيفرة الآتية واحفظها في الملف <code>yourName.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_42" style=""><span class="pun">➊</span><span class="pln"> name </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="kwd">while</span><span class="pln"> name </span><span class="pun">!=</span><span class="pln"> </span><span class="str">'your name'</span><span class="pun">:</span><span class="pln">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Please type your 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="pln">
</span><span class="pun">➍</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Thank you!'</span><span class="pun">)</span></pre>

<p>
	يضبط البرنامجُ المتغيرَ <code>name</code> إلى سلسلة نصية فارغة ➊، وبهذا يكون الشرط <code>name != 'your name'‎</code> محققًا <code>True</code> وبالتالي سيبدأ تنفيذ حلقة <code>while</code> ➋.
</p>

<p>
	سيسأل البرنامجُ المستخدمَ عن اسمه، ثم يأخذ المدخلات ويخزنها في المتغير <code>name</code> ➌، ولمّا كنّا قد وصلنا إلى نهاية حلقة التكرار فسنعود إلى بداية حلقة <code>while</code> ونتحقق من الشرط، وإن لم يكن الاسم name مساويًا إلى السلسلة النصية <code>'your name'</code> فيسكون الشرط محققًا <code>True</code> وسيعاد تنفيذ حلقة <code>while</code> مجددًا.
</p>

<p>
	لكن حينما يدخل المستخدم الكلمتين your name فسيصبح شرط حلقة <code>while</code> غير محقق <code>False</code>، وبالتالي بدلًا من إعادة تكرار الحلقة فسيكمل برنامجنا تنفيذ بقية البرنامج ➍.
</p>

<p>
	المخطط التدفقي في الشكل الآتي يوضح آلية عمل البرنامج <code>yourName.py</code>:
</p>

<p style="text-align: center;">
	<img alt="18-yourname-flowchart.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="150276" data-ratio="94.94" data-unique="oizkmtfji" style="width: 400px; height: auto;" width="573" src="https://academy.hsoub.com/uploads/monthly_2024_05/18-yourname-flowchart.jpg.f5516446a2dd558f5402b407c9ec064e.jpg">
</p>

<p style="text-align: center;">
	المخطط التدفقي للبرنامج <code>yourName.py</code>.
</p>

<p>
	لنجرب الآن البرنامج، بالضغط على زر F5 لتشغيله، ثم كتابة أي عبارة سوى "your name" عدة مرات قبل أن نرضخ للضغط الذي يمارسه البرنامج تجاهنا ونكتب "your name".
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_44" style=""><span class="typ">Please</span><span class="pln"> type your name</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Abdullatif</span><span class="pln">
</span><span class="typ">Please</span><span class="pln"> type your name</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Hsoub</span><span class="pln">
</span><span class="typ">Please</span><span class="pln"> type your name</span><span class="pun">.</span><span class="pln">
</span><span class="pun">%#@#%*(^&amp;!!!</span><span class="pln">
</span><span class="typ">Please</span><span class="pln"> type your name</span><span class="pun">.</span><span class="pln">
your name
</span><span class="typ">Thank</span><span class="pln"> you</span><span class="pun">!</span></pre>

<p>
	إذا لم ندخل "your name" أبدًا فلن يصبح شرط <code>while</code> غير محقق <code>False</code> وبالتالي سيستمر تنفيذ البرنامج إلى الأبد. وفي حالة برنامجنا كانت لدينا الدالة input()<code>‎</code> التي تمكننا من إكمال سير البرنامج حينما ندخل العبارة الصحيحة وبالتالي تتغير حالة الشرط، لكن قد لا يتغير الشرط في بعض البرامج مما يسبب مشكلة، لذا هنالك حاجة لتعلم طريقة للخروج من حلقة <code>while</code>.
</p>

<h3 id="break">
	العبارة break
</h3>

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

<p>
	أليس ذلك بسيطًا؟ لنكتب برنامجًا يشبه البرنامج السابق لكنه يستخدم العبارة <code>break</code> للخروج من حلقة التكرار، أدخِل الشيفرة الآتية واحفظها في ملف باسم <code>yourName2.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_46" style=""><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">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Please type your 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="pln">
    </span><span class="pun">➌</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> name </span><span class="pun">==</span><span class="pln"> </span><span class="str">'your name'</span><span class="pun">:</span><span class="pln">
        </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="kwd">print</span><span class="pun">(</span><span class="str">'Thank you!'</span><span class="pun">)</span></pre>

<p>
	ننشِئ في أول سطر ➊ حلقة تكرار لا نهائية، وذلك بجعل شرط حلقة <code>while</code> محققًا دومًا <code>True</code>، وبالتأكيد إذا وضعنا <code>True</code> شرطًا لحلقة <code>while</code> فستكون قيمته هي <code>True</code> دومًا.
</p>

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

<p>
	وكما في المثال السابق، سيطلب البرنامج من المستخدم أن يدخل your name ➋، وسنتحقق إن كان المتغير <code>name</code> يساوي 'your name' باستخدام البنية الشرطية <code>if</code> ➌، وإذا كان الشرط محققًا <code>True</code> فستنفذ العبارة <code>break</code> ➍، وسينتقل التنفيذ إلى خارج الحلقة وستطبع رسالة الشكر ➎.
</p>

<p>
	إذا لم يكن شرط العبارة if محققًا فهذا يؤدي إلى دورة جديدة لحلقة <code>while</code>، وسيتحقق البرنامج من شرط تنفيذ حلقة <code>while</code> ➊، ولمّا كان الشرط محققًا <code>True</code> دومًا، فستنفذ حلقة التكرار مجددًا وتسأل المستخدم أن يدخل your name.
</p>

<p>
	المخطط التدفقي في الشكل التالي يوضح آلية عمل البرنامج <code>yourName2.py</code>:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150277" href="https://academy.hsoub.com/uploads/monthly_2024_05/19-yourname2-flowchart.jpg.b4731f9fd19ad58396b4dd104e6ab55f.jpg" rel=""><img alt="19-yourname2-flowchart.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="150277" data-ratio="97.72" data-unique="sqsc5rhyw" style="width: 500px; height: auto;" width="614" src="https://academy.hsoub.com/uploads/monthly_2024_05/19-yourname2-flowchart.thumb.jpg.16c68338646d72a03bb01a06abcc931e.jpg"></a>
</p>

<p style="text-align: center;">
	المخطط التدفقي للبرنامج <code>yourName2.py</code> مع حلقة تكرار لا نهائية، لاحظ أن المسار <code>×</code> لا ينفذ منطقيًا أبدًا لأن شرط الحلقة هو <code>True</code> دومًا.
</p>

<h3 id="-10">
	هل وقعت في حلقة تكرار لا نهائية؟
</h3>

<p>
	إذا شغلت تطبيقًا يحتوي على علة تؤدي إلى حلقة تكرار لا نهائية، فاضغط على <code>Ctrl+C</code> أو أعد تشغيل الصدفة من Shell ثم Restart Shell؛ مما يرسل إشارة KeyboardInterrupt إلى برنامجك تؤدي إلى إيقاف تشغيله مباشرةً. يمكنك التجربة بإنشاء برنامج بسيط باسم <code>infiniteLoop.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_48" style=""><span class="kwd">while</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hello, world!'</span><span class="pun">)</span></pre>

<p>
	سيطبع البرنامج السابق العبارة Hello, World!‎ إلى اللانهاية لأن شرط حلقة <code>while</code> محقق <code>True</code> دومًا. قد تستفيد من استخدام الاختصار <code>Ctrl+C</code> لإنهاء تنفيذ البرامج حتى دون أن تكون عالقًا في حلقة تكرار لا نهائية.
</p>

<h3 id="continue">
	عبارة continue
</h3>

<p>
	وكما في عبارة <code>break</code>، نستعمل <a href="https://wiki.hsoub.com/Python/for#.D8.B9.D8.A8.D8.A7.D8.B1.D8.A9_continue" rel="external">العبارة continue</a> داخل حلقات التكرار، وحينما يصل التنفيذ إلى عبارة <code>continue</code> فسينتقل تنفيذ البرنامج إلى بداية حلقة التكرار مباشرةً ويعيد التحقق من شرط الحلقة، أي نفس ما يحدث حين الوصول إلى نهاية دورة حلقة التكرار.
</p>

<p>
	لنستخدم <code>continue</code> لكتابة برنامج يسأل عن اسم المستخدم وكلمة المرور، أدخل ما يلي في ملف جديد واحفظه باسم <code>swordfish.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_50" style=""><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">
      </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Who are you?'</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="pln">
    </span><span class="pun">➊</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> name </span><span class="pun">!=</span><span class="pln"> </span><span class="str">'Abdullatif'</span><span class="pun">:</span><span class="pln">
        </span><span class="pun">➋</span><span class="pln"> </span><span class="kwd">continue</span><span class="pln">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hello, Abdullatif. What is the password? (It is a fish.)'</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">➌</span><span class="pln"> password </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> password </span><span class="pun">==</span><span class="pln"> </span><span class="str">'swordfish'</span><span class="pun">:</span><span class="pln">
        </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="kwd">print</span><span class="pun">(</span><span class="str">'Access granted.'</span><span class="pun">)</span><span class="pln">    </span></pre>

<p>
	إذا أدخل المستخدم أي اسم باستثناء Abdullatif ➊ فستنقل العبارة <code>continue</code> ➋ التنفيذ إلى بداية حلقة التكرار، وحين إعادة التحقق من شرط الدخول إلى الحلقة فسيكون محققًا دومًا لأنه <code>True</code>.
</p>

<p>
	بعد أن يتجاوز المستخدم الشرط الموجود في <code>if</code> فسنسأله عن كلمة المرور ➌، وإذا أدخل كلمة المرور swordfish فستنفذ عبارة <code>break</code> ➍ وبالتالي نخرج من حلقة التكرار كليًا وستطبع العبارة Access granted ➎، وإذا لم تكن كلمة المرور صحيحةً فسنصل إلى نهاية دورة حلقة التكرار ثم نعود إلى بدايتها ونتحقق من الشرط مجددًا الذي هو True دومًا… المخطط التدفقي في الشكل الآتي يوضح آلية عمل البرنامج <code>swordfish.py</code>:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="150268" href="https://academy.hsoub.com/uploads/monthly_2024_05/20-swordfish-flowchart-.jpg.9e8402a62eceb6910b32e5da87c0e82e.jpg" rel=""><img alt="20-swordfish-flowchart-معرب.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="150268" data-ratio="137.30" data-unique="9l5eumx2b" width="437" src="https://academy.hsoub.com/uploads/monthly_2024_05/20-swordfish-flowchart-.thumb.jpg.7127e42ea7126c8b9311c6e95ab749e8.jpg"></a>
</p>

<p style="text-align: center;">
	المخطط التدفقي للبرنامج <code>swordfish.py</code>، لاحظ أن المسار <code>×</code> لا ينفذ منطقيًا أبدًا لأن شرط الحلقة هو <code>True</code> دومًا.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_52" style=""><span class="typ">Who</span><span class="pln"> are you</span><span class="pun">?</span><span class="pln">
I</span><span class="str">'m fine, thanks. Who are you?
Who are you?
Abdullatif
Hello, Abdullatif. What is the password? (It is a fish.)
Mary
Who are you?
Abdullatif
Hello, Abdullatif. What is the password? (It is a fish.)
swordfish
Access granted.</span></pre>

<h4 id="truefalse">
	القيم التي تكافئ True والقيم التي تكافئ False
</h4>

<p>
	ستعدّ الشروط في بايثون بعض القيم في أنواع البيانات المختلفة على أنها مكافئة للقيمة <code>True</code> وأخرى للقيمة <code>False</code>. فلو استخدمنا القيم 0 و 0.0 و '' (سلسلة نصية فارغة) في الشروط فستكافئ <code>False</code>، بينما ستكافئ أي قيمة أخرى <code>True</code>. ألقِ نظرةً هنا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_54" style=""><span class="pln">name </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="kwd">while</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> name</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Enter your name:'</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="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'How many guests will you have?'</span><span class="pun">)</span><span class="pln">
numOfGuests </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="pln">
</span><span class="pun">➋</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> numOfGuests</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="str">'Be sure to have enough room for all your guests.'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Done'</span><span class="pun">)</span></pre>

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

<p>
	سيبدأ تنفيذ الحلقة بطلب إدخال الاسم وعدد الضيوف، وإذا كان عدد الضيوف numOfGuests ليس صفرًا 0 ➋ فسيكون الشرط محققًا <code>True</code> وسيطبع البرنامج تذكيرًا للمستخدم ➌.
</p>

<p>
	كان بإمكاننا كتابة name != ''<code>‎</code> بدلًا من <code>not name</code>، و <code>numOfGuests != 0</code> بدلًا من numOfGuests، لكن استخدام القيم التي تكافئ <code>True</code> أو <code>False</code> في شروط سيجعل مقروئية شيفرتك أفضل.
</p>

<h3 id="forrange">
	حلقات تكرار for والدالة range()‎
</h3>

<p>
	ستعمل <a href="https://wiki.hsoub.com/Python/while" rel="external">حلقة while</a> لطالما كان الشرط محققًا <code>True</code> (ومن هنا أتى اسمها while)، لكن ماذا لو أردنا تنفيذ كتلة من الشيفرات لعدد محدد من المرات؟ يمكننا فعل ذلك عبر <a href="https://wiki.hsoub.com/Python/for" rel="external">حلقة التكرار for</a> و<a href="https://wiki.hsoub.com/Python/for#.D8.A7.D9.84.D8.AF.D8.A7.D9.84.D8.A9_range.28.29" rel="external">الدالة range()</a>.
</p>

<p>
	ستبدو عبارة <code>for</code> كالآتي <code>for i in range(5):</code> وستتضمن ما يلي:
</p>

<ul>
	<li>
		الكلمة المحجوزة <code>for</code>
	</li>
	<li>
		اسم المتغير
	</li>
	<li>
		الكلمة المحجوزة <code>in</code>
	</li>
	<li>
		استدعاء للدالة <code>range()‎</code> مع تمرير 3 أعداد صحيحة كحد أقصى إليها
	</li>
	<li>
		نقطتان رأسيتان <code>:</code>
	</li>
	<li>
		كتلة برمجية تلي ما سبق، تكون فيها الأسطر مسبوقة بمسافة بادئة
	</li>
</ul>

<p>
	لننشئ برنامجًا ولنسمه <code>fiveTimes.py</code> الذي يساعدنا على معاينة حلقة <code>for</code> عمليًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_56" style=""><span class="kwd">print</span><span class="pun">(</span><span class="str">'My name is'</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">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hani Five Times ('</span><span class="pln"> </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="str">')'</span><span class="pun">)</span></pre>

<p>
	سترى أن الكتلة البرمجية لحلقة التكرار <code>for</code> تنفذ 5 مرات، وستكون قيمة المتغير <code>i</code> في أول مرة تعمل فيها الحلقة هو 0، وستطبع <code>print()‎</code> العبارة Hani Five Times (0)‎ ثم بعد أن تنتهي بايثون من تنفيذ أول دورة في حلقة التكرار فسيعود التنفيذ إلى بداية الحلقة وستزيد قيمة المتغير <code>i</code> بمقدار 1، ولهذا سيؤدي استدعاء الدالة range(5)‎ إلى حدوث 5 تكرارات داخل حلقة <code>for</code>، إذ سيبدأ المتغير i من القيمة 0 ثم 1 ثم 2 ثم 3 ثم 4، وعمومًا ستزداد قيمة المتغير إلى أن تصل إلى الرقم الذي مررناه إلى الدالة range()‎ لكن دون تضمينه في النتائج.
</p>

<p>
	الشكل الآتي يوضح المخطط التدفقي لهذا البرنامج:
</p>

<p style="text-align: center;">
	<img alt="21-fiveTimes-flowchart-معرب-.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="150269" data-ratio="79.84" data-unique="va5k3cp4k" style="width: 400px; height: auto;" width="610" src="https://academy.hsoub.com/uploads/monthly_2024_05/21-fiveTimes-flowchart--.jpg.d8691443379882c67b998b4dc3bca530.jpg">
</p>

<p>
	إذا شغلت البرنامج فسترى العبارة Hani Five Times متبوعةً بقيمة المتغير i في دورة حلقة <code>for</code> الحالية:
</p>

<pre class="ipsCode" id="ips_uid_5380_60">My name is
Hani Five Times (0)
Hani Five Times (1)
Hani Five Times (2)
Hani Five Times (3)
Hani Five Times (4)</pre>

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

<p>
	لنأخذ قصة عالم الرياضيات الشهير كارل فريدريش غاوس (قد تعرفه باسم غاوس أو Gauss)، أراد مدرسه حينما كان صغيرًا أن يعطيه وظيفة صعبة وطلب منه جمع الأرقام من 0 إلى 100، وخطرت ببال الفتى غاوس طريقة ذكية للإجابة عن ذاك السؤال بثوانٍ معدودة، لكن لنكتب الآن برنامج بايثون يحسب لنا الناتج ويستعمل الحلقة <code>for</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_62" style=""><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="pun">➋</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> num </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">101</span><span class="pun">):</span><span class="pln">
    </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"> num
</span><span class="pun">➍</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">total</span><span class="pun">)</span></pre>

<p>
	يفترض أن يكون الناتج 5,050. نضبط قيمة المتغير <code>total</code> إلى 0 ➊ في بداية البرنامج، ثم نبدأ حلقة for ➋ التي ننفذ فيها <code>total = total + num</code> ➌ مئة مرة، وبعد أن تنتهي دورات التكرار المئة فسنكون قد جمعنا الأعداد الصحيحة من 0 إلى 100 في المتغير <code>total</code>، ثم نطبق قيمة <code>total</code> إلى الشاشة ➍. سيعمل برنامجنا بأجزاء من الثانية ويخبرنا بالناتج النهائي.
</p>

<p>
	(اكتشف غاوس حينما أعطاه المدرس هذه الوظيفة حلها بطريقة ذكية: هنالك خمسون زوجًا من الأرقام التي يكون مجموعها 101 مثل 1 + 100 و 2 + 99 و 3 + 98 وهلمَّ جرًا، حتى يصل إلى 50 + 51. ولمّا كان جداء 50 × 101 هو 5,050 فسيكون مجموع جميع الأرقام من 0 إلى 100 هو 5,050. يا له من فتى ذكي!)
</p>

<h3 id="whilefor">
	كتابة حلقة while تكافئ حلقة for
</h3>

<p>
	يمكنك عمليًا أن تكتب حلقة <code>while</code> لتكافئ في عملها حلقة <code>for</code>، وستجد أن كتابة حلقات <code>for</code> مختصرة أكثر. لنعد كتابة المثال <code>iveTimes.py</code> ليستعمل الحلقة <code>while</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_64" style=""><span class="kwd">print</span><span class="pun">(</span><span class="str">'My name is'</span><span class="pun">)</span><span class="pln">
i </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"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hani Five Times ('</span><span class="pln"> </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="str">')'</span><span class="pun">)</span><span class="pln">
    i </span><span class="pun">=</span><span class="pln"> i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span></pre>

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

<h3 id="range">
	وسائط الدالة range()‎: البداية والنهاية والخطوة
</h3>

<p>
	يمكن أن تستدعى بعض الدوال مع عدّة وسائط arguments مفصولة بفاصلة، والدالة range()‎ هي إحداها.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_66" style=""><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">12</span><span class="pun">,</span><span class="pln"> </span><span class="lit">16</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span></pre>

<p>
	يمثِّل أول وسيط من أين يجب أن تبدأ حلقة <code>for</code>، ويمثل الوسيط الثاني أين يجب أن تتوقف (دون تضمين هذا الرقم):
</p>

<pre class="ipsCode">12
13
14
15
</pre>

<p>
	يمكننا أيضًا استدعاء الدالة range()‎ مع ثلاثة وسائط، ويكون أول وسيطين هما البداية والنهاية، أما الوسيط الثالث فسيكون «الخطوة» step، الذي يشير إلى مقدار زيادة قيمة المتغير عند كل دورة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_68" style=""><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">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </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">i</span><span class="pun">)</span></pre>

<p>
	أي أن استدعاء range(0, 10, 2)‎ سيعد من الصفر إلى الثمانية وبخطوة 2:
</p>

<pre class="ipsCode">0
2
4
6
8
</pre>

<p>
	الدالة range()‎ مرنة ويمكنك استخدامها لتوليد أي سلسلة أرقام، فمثلًا يمكنك استخدام رقم سالب كوسيط لقيمة الخطوة مما يؤدي إلى العد عكسيًا تنازليًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_70" style=""><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"> </span><span class="pun">-</span><span class="lit">1</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">print</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span></pre>

<p>
	ستنتج حلقة <code>for</code> السابقة الناتج الآتي:
</p>

<pre class="ipsCode">5
4
3
2
1
0
</pre>

<p>
	نجد أن المجال range(5, -1, -1)‎ مع حلقة التكرار <code>for</code> سيؤدي إلى طباعة 5 أعداد تنازليًا من 5 إلى 0.
</p>

<h2 id="-11">
	استيراد الوحدات
</h2>

<p>
	يمكن لجميع برامج بايثون أن تستدعي مجموعةً من الدوال الأساسية نسميها الدوال المضمنة في اللغة أو «الدوال المضمنة» built-in functions، والتي تتضمن الدوال التي تعرفت عليها سابقًا مثل print()‎ و input()‎ و len()‎.
</p>

<p>
	تأتي بايثون أيضًا مع مجموعة من الوحدات الأساسية modules التي نسميها بالمكتبة القياسية standard library. تتألف كل وحدة من عدد برامج بايثون التي فيها مجموعة من الدوال التي يمكنك استخدامها في برامجك.
</p>

<p>
	فمثلًا تحتوي الوحدة math على مجموعة من الدوال المتعلقة بالعمليات الرياضية، بينما تضم الوحدة random مجموعة من الدوال التي تجري عمليات على الأرقام المولدة عشوائيًا، وهكذا.
</p>

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

<ul>
	<li>
		الكلمة المحجوزة <code>import</code>
	</li>
	<li>
		اسم الوحدة التي نريد استيرادها
	</li>
	<li>
		واختياريًا أسماء وحدات أخرى نريد استيرادها على أن نفصل بينها بفاصلة
	</li>
</ul>

<p>
	بعد أن تستورد إحدى الوحدات فيمكنك أن تستعمل جميع الدوال الرائعة الموجودة فيها، ولنضرب مثالًا الوحدة <code>random</code> التي تمنحنا وصولًا إلى الدالة random.randint()‎ حين استيرادها.
</p>

<p>
	احفظ الشيفرة الآتية في ملف باسم <code>printRandom.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_72" style=""><span class="kwd">import</span><span class="pln"> random
</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">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">random</span><span class="pun">.</span><span class="pln">randint</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">))</span></pre>

<p>
	سيطبع البرنامج السابق ناتجًا يشبه الناتج الآتي حين تشغيله:
</p>

<pre class="ipsCode">4
1
8
4
1
</pre>

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

<p>
	هذا مثال لعبارة استيراد تستورد أربع وحدات في آنٍ واحد:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_74" style=""><span class="kwd">import</span><span class="pln"> random</span><span class="pun">,</span><span class="pln"> sys</span><span class="pun">,</span><span class="pln"> os</span><span class="pun">,</span><span class="pln"> math</span></pre>

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

<h3 id="fromimport">
	عبارة from import
</h3>

<p>
	هنالك شكل بديل لعبارة <code>import</code> يتضمن الكلمة المحجوزة <code>from</code>، والتي نتبعها باسم الوحدة، ثم الكلمة المحجوزة <code>import</code> ثم نجمة <code>*</code>؛ فمثلًا <code>from random import *‎</code>.
</p>

<p>
	وحين استيراد الوحدات بهذا الشكل فلا حاجة إلى وضع السابقة <code>random.‎</code> قبل أسماء الدوال التي نريد استدعاءها؛ لكن في المقابل من الأفضل كتابة الاسم الكامل للدالة مع السابقة التي تشير إلى اسم الوحدة لزيادة مقروئية الشيفرة البرمجية.
</p>

<h2 id="sysexit">
	إنهاء تنفيذ البرنامج حينما نشاء باستخدام الدالة sys.exit()‎
</h2>

<p>
	آخر مفهوم من مفاهيم بنى التحكم التي سنشرحها في هذا المقال هو آلية إنهاء تنفيذ البرنامج.
</p>

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

<p>
	افتح محرر الشيفرات واكتب ما يلي واحفظه <code>exitExample.py</code>:
</p>

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

</span><span class="kwd">while</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Type exit to exit.'</span><span class="pun">)</span><span class="pln">
    response </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> response </span><span class="pun">==</span><span class="pln"> </span><span class="str">'exit'</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="kwd">print</span><span class="pun">(</span><span class="str">'You typed '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> response </span><span class="pun">+</span><span class="pln"> </span><span class="str">'.'</span><span class="pun">)</span></pre>

<p>
	شغل البرنامج السابق وستجد أنك دخلت في حلقة تكرار لا نهائية دون وجود عبارة <code>break</code> داخلها، والطريقة الوحيدة لكي ينتهي تنفيذ البرنامج هي الوصول إلى استدعاء الدالة sys.exit()‎، ولأن قيمة المتغير <code>response</code> تساوي ما يدخله المستخدم عبر input()‎، فإذا أدخلت <code>exit</code> فستتحقق العبارة الشرطية <code>if</code> وسينتهي تنفيذ البرنامج.
</p>

<h2 id="-12">
	برنامج قصير: احزر الرقم
</h2>

<p>
	جميع الأمثلة السابقة كانت بسيطة جدًا لكنها مناسبة لاستيعاب المفاهيم البرمجية الأساسية، لكن لنبني الآن برنامجًا متكاملًا نوظِّف فيه المعلومات التي تعلمناها. سنكتب في هذا القسم لعبة «احزر الرقم»، والتي ستبدو كما يلي حين تشغيلها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_78" style=""><span class="pln">I am thinking of a number between </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">20.</span><span class="pln">
</span><span class="typ">Take</span><span class="pln"> a guess</span><span class="pun">.</span><span class="pln">
</span><span class="lit">10</span><span class="pln">
</span><span class="typ">Your</span><span class="pln"> guess </span><span class="kwd">is</span><span class="pln"> too low</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Take</span><span class="pln"> a guess</span><span class="pun">.</span><span class="pln">
</span><span class="lit">15</span><span class="pln">
</span><span class="typ">Your</span><span class="pln"> guess </span><span class="kwd">is</span><span class="pln"> too low</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Take</span><span class="pln"> a guess</span><span class="pun">.</span><span class="pln">
</span><span class="lit">17</span><span class="pln">
</span><span class="typ">Your</span><span class="pln"> guess </span><span class="kwd">is</span><span class="pln"> too high</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Take</span><span class="pln"> a guess</span><span class="pun">.</span><span class="pln">
</span><span class="lit">16</span><span class="pln">
</span><span class="typ">Good</span><span class="pln"> job</span><span class="pun">!</span><span class="pln"> </span><span class="typ">You</span><span class="pln"> guessed my number </span><span class="kwd">in</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> guesses</span><span class="pun">!</span></pre>

<p>
	افتح محرر الشيفرات وأدخل الشيفرة الآتية واحفظها في ملف باسم <code>guessTheNumber.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_80" style=""><span class="com"># This is a guess the number game.</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> random
secretNumber </span><span class="pun">=</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">randint</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">20</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'I am thinking of a number between 1 and 20.'</span><span class="pun">)</span><span class="pln">

</span><span class="com"># Ask the player to guess 6 times.</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> guessesTaken </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="pln"> </span><span class="lit">7</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Take a guess.'</span><span class="pun">)</span><span class="pln">
    guess </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="pln">

    </span><span class="kwd">if</span><span class="pln"> guess </span><span class="pun">&lt;</span><span class="pln"> secretNumber</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Your guess is too low.'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> guess </span><span class="pun">&gt;</span><span class="pln"> secretNumber</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Your guess is too high.'</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">break</span><span class="pln">    </span><span class="com"># This condition is the correct guess!</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> guess </span><span class="pun">==</span><span class="pln"> secretNumber</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Good job! You guessed my number in '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">guessesTaken</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'
guesses!'</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="str">'Nope. The number I was thinking of was '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">secretNumber</span><span class="pun">))</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_82" style=""><span class="com"># This is a guess the number game.</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> random
secretNumber </span><span class="pun">=</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">randint</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">20</span><span class="pun">)</span></pre>

<p>
	يبدأ البرنامج بتعليق في أول سطر فيه يشرح ماذا يفعل البرنامج، ثم يستورد الوحدة <code>random</code> لكي نستطيع استخدام الدالة random.randint()‎ لتوليد رقم ليحزره اللاعب، وسنخزن الرقم العشوائي الناتج في المتغير <code>secretNumber</code>.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_84" style=""><span class="kwd">print</span><span class="pun">(</span><span class="str">'I am thinking of a number between 1 and 20.'</span><span class="pun">)</span><span class="pln">

</span><span class="com"># Ask the player to guess 6 times.</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> guessesTaken </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="pln"> </span><span class="lit">7</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Take a guess.'</span><span class="pun">)</span><span class="pln">
    guess </span><span class="pun">=</span><span class="pln"> int</span><span class="pun">(</span><span class="pln">input</span><span class="pun">())</span></pre>

<p>
	سيخبر البرنامج اللاعب أنه قد «فكر» في رقم سري ويملك اللاعب ست محاولات ليحزره، وستكون الشيفرة التي تسمح للاعب بإدخال رقم والتحقق منه موجودة في حلقة <code>for</code> التي ستنفذ ست مرات كحد أقصى.
</p>

<p>
	أول ما تفعله حلقة التكرار هو طلب كتابة تخمين للرقم السري عبر input()‎، ولأن الدالة input()‎ تعيد سلسلةً نصية وليس رقمًا صحيحًا فنمرر الناتج إلى الدالة int()‎، وثم يخزن الرقم الذي أدخله المستخدم في المتغير <code>guess</code>.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_86" style=""><span class="pln">    </span><span class="kwd">if</span><span class="pln"> guess </span><span class="pun">&lt;</span><span class="pln"> secretNumber</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Your guess is too low.'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> guess </span><span class="pun">&gt;</span><span class="pln"> secretNumber</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Your guess is too high.'</span><span class="pun">)</span></pre>

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

<pre class="ipsCode">    else:
        break    # This condition is the correct guess!
</pre>

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

<pre class="ipsCode">if guess == secretNumber:
    print('Good job! You guessed my number in ' + str(guessesTaken) + ' guesses!')
else:
    print('Nope. The number I was thinking of was ' + str(secretNumber))
</pre>

<p>
	بعد نهاية حلقة for سيتحقق البرنامج عبر عبارة <code>if…else</code> أن اللاعب قد خمَّن الرقم السري الصحيح، ويعرض رسالة مناسبة لكل حالة. تذكر أن الشيفرات التي تقع بعد حلقة التكرار ستنفذ بعد انتهاء تنفيذ حلقة التكرار سواءً بإكمالها 6 مرات وعدم تخمين اللاعب للرقم الصحيح، أو بالخروج منها عبر <code>break</code> حين تخمين الرقم السري الصحيح.
</p>

<p>
	سيعرض برنامجنا رسالتين نصيتين فيهما متغير يحمل قيمةً عدديةً صحيحةً guessesTaken و secretNumber، ولأننا نحاول ضم عدد صحيح إلى سلسلة نصية فيجب أن نمرر الرقم إلى الدالة str()‎ أولًا، ثم نضم السلاسل النصية عبر العامل + لتمريرها إلى الدالة print()‎ لطباعتها على الشاشة.
</p>

<h2 id="-13">
	برنامج قصير: حجرة ورقة مقص
</h2>

<p>
	لنستخدم المفاهيم البرمجية التي تعلمناها لإنشاء لعبة «حجرة ورقة مقص» الشهيرة. سيكون ناتج تشغيل اللعبة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_88" style=""><span class="pln">ROCK</span><span class="pun">,</span><span class="pln"> PAPER</span><span class="pun">,</span><span class="pln"> SCISSORS
</span><span class="lit">0</span><span class="pln"> </span><span class="typ">Wins</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="typ">Losses</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="typ">Ties</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> your move</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">r</span><span class="pun">)</span><span class="pln">ock </span><span class="pun">(</span><span class="pln">p</span><span class="pun">)</span><span class="pln">aper </span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln">cissors </span><span class="kwd">or</span><span class="pln"> </span><span class="pun">(</span><span class="pln">q</span><span class="pun">)</span><span class="pln">uit
p
PAPER versus</span><span class="pun">...</span><span class="pln">
PAPER
</span><span class="typ">It</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> a tie</span><span class="pun">!</span><span class="pln">
</span><span class="lit">0</span><span class="pln"> </span><span class="typ">Wins</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="typ">Losses</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="typ">Ties</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> your move</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">r</span><span class="pun">)</span><span class="pln">ock </span><span class="pun">(</span><span class="pln">p</span><span class="pun">)</span><span class="pln">aper </span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln">cissors </span><span class="kwd">or</span><span class="pln"> </span><span class="pun">(</span><span class="pln">q</span><span class="pun">)</span><span class="pln">uit
s
SCISSORS versus</span><span class="pun">...</span><span class="pln">
PAPER
</span><span class="typ">You</span><span class="pln"> win</span><span class="pun">!</span><span class="pln">
</span><span class="lit">1</span><span class="pln"> </span><span class="typ">Wins</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="typ">Losses</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="typ">Ties</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> your move</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">r</span><span class="pun">)</span><span class="pln">ock </span><span class="pun">(</span><span class="pln">p</span><span class="pun">)</span><span class="pln">aper </span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln">cissors </span><span class="kwd">or</span><span class="pln"> </span><span class="pun">(</span><span class="pln">q</span><span class="pun">)</span><span class="pln">uit
q</span></pre>

<p>
	افتح نافذةً جديدةً في محرر الشيفرات وأدخل الشيفرة الآتية واحفظها في ملف باسم <code>rpsGame.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_90" style=""><span class="kwd">import</span><span class="pln"> random</span><span class="pun">,</span><span class="pln"> sys

</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'ROCK, PAPER, SCISSORS'</span><span class="pun">)</span></pre>

<p>
	ستتبّع هذه المتغيرات عدد مرات الربح والخسارة والتعادل
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_92" style=""><span class="pln">wins </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
losses </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
ties </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"> </span><span class="kwd">True</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="str">'%s Wins, %s Losses, %s Ties'</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">wins</span><span class="pun">,</span><span class="pln"> losses</span><span class="pun">,</span><span class="pln"> ties</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"> </span><span class="com"># مدخلات المستخدم</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Enter your move: (r)ock (p)aper (s)cissors or (q)uit'</span><span class="pun">)</span><span class="pln">
        playerMove </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'q'</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">
        </span><span class="kwd">if</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'r'</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'p'</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'s'</span><span class="pun">:</span><span class="pln">
            </span><span class="kwd">break</span><span class="pln"> </span><span class="com"># الخروج من حلقة مدخلات المستخدم</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Type one of r, p, s, or q.'</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"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'r'</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'ROCK versus...'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'p'</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'PAPER versus...'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'s'</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'SCISSORS versus...'</span><span class="pun">)</span><span class="pln">

    </span><span class="com"># عرض ما اختاره الحاسوب</span><span class="pln">
    randomNumber </span><span class="pun">=</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">randint</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> randomNumber </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
        computerMove </span><span class="pun">=</span><span class="pln"> </span><span class="str">'r'</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'ROCK'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> randomNumber </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
        computerMove </span><span class="pun">=</span><span class="pln"> </span><span class="str">'p'</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'PAPER'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> randomNumber </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pun">:</span><span class="pln">
        computerMove </span><span class="pun">=</span><span class="pln"> </span><span class="str">'s'</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'SCISSORS'</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"> playerMove </span><span class="pun">==</span><span class="pln"> computerMove</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'It is a tie!'</span><span class="pun">)</span><span class="pln">
        ties </span><span class="pun">=</span><span class="pln"> ties </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'r'</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> computerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'s'</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You win!'</span><span class="pun">)</span><span class="pln">
        wins </span><span class="pun">=</span><span class="pln"> wins </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'p'</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> computerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'r'</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You win!'</span><span class="pun">)</span><span class="pln">
        wins </span><span class="pun">=</span><span class="pln"> wins </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'s'</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> computerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'p'</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You win!'</span><span class="pun">)</span><span class="pln">
        wins </span><span class="pun">=</span><span class="pln"> wins </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'r'</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> computerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'p'</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You lose!'</span><span class="pun">)</span><span class="pln">
        losses </span><span class="pun">=</span><span class="pln"> losses </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'p'</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> computerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'s'</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You lose!'</span><span class="pun">)</span><span class="pln">
        losses </span><span class="pun">=</span><span class="pln"> losses </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'s'</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> computerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'r'</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You lose!'</span><span class="pun">)</span><span class="pln">
        losses </span><span class="pun">=</span><span class="pln"> losses </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span></pre>

<p>
	لنمعن النظر إلى الشيفرة من بدايتها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_94" style=""><span class="kwd">import</span><span class="pln"> random</span><span class="pun">,</span><span class="pln"> sys

</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'ROCK, PAPER, SCISSORS'</span><span class="pun">)</span><span class="pln">

</span><span class="com"># ستتبّع هذه المتغيرات عدد مرات الربح والخسارة والتعادل</span><span class="pln">
wins </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
losses </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
ties </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span></pre>

<p>
	سنستورد في البداية الوحدتين <code>random</code> و <code>sys</code> لكي نستطيع استدعاء الدالتين random.randint()‎ و sys.exit()‎، ثم سنهيئ ثلاثة متغيرات لكي نتتبع عدد مرات ربح أو خسارة أو تعادل اللاعب.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_96" style=""><span class="kwd">while</span><span class="pln"> </span><span class="kwd">True</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="str">'%s Wins, %s Losses, %s Ties'</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">wins</span><span class="pun">,</span><span class="pln"> losses</span><span class="pun">,</span><span class="pln"> ties</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"> </span><span class="com"># مدخلات المستخدم</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Enter your move: (r)ock (p)aper (s)cissors or (q)uit'</span><span class="pun">)</span><span class="pln">
        playerMove </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'q'</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">
        </span><span class="kwd">if</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'r'</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'p'</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'s'</span><span class="pun">:</span><span class="pln">
            </span><span class="kwd">break</span><span class="pln"> </span><span class="com"># الخروج من حلقة مدخلات المستخدم</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Type one of r, p, s, or q.'</span><span class="pun">)</span></pre>

<p>
	يستعمل برنامجنا حلقة <code>while</code> داخل حلقة <code>while</code>، أول حلقة هي حلقة اللعبة الأساسية، وتمثل دورًا من لعبة «حجرة ورقة مقص» في كل مرة تنفذ فيها تلك الحلقة. أما حلقة التكرار الثانية فهي تطلب من اللاعب مدخلات، وستبقى تعمل حتى يدخل المستخدم r أو p أو s أو q التي ترمز إلى حجرة rock وورقة paper ومقص scissors على التوالي وبالترتيب، أما q فتعني أن اللاعب يريد إنهاء اللعبة quit، وفي تلك الحالة ستستدعى الدالة sys.exit()‎ وسنتهي تنفيذ البرنامج.
</p>

<p>
	إذا أدخل المستخدم r أو p أو s فسنخرج من حلقة التكرار الثانية عبر <code>break</code>، وإلا فسيعود التنفيذ إلى بداية حلقة التكرار ويذكر البرنامج اللاعب أن عليه إدخال r أو p أو s أو q.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_98" style=""><span class="pln">    </span><span class="com"># عرض ما اختاره اللاعب</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'r'</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'ROCK versus...'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'p'</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'PAPER versus...'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'s'</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'SCISSORS versus...'</span><span class="pun">)</span></pre>

<p>
	يظهر البرنامج هنا ما اختاره اللاعب.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_100" style=""><span class="pln">    </span><span class="com"># عرض ما اختاره الحاسوب</span><span class="pln">
    randomNumber </span><span class="pun">=</span><span class="pln"> random</span><span class="pun">.</span><span class="pln">randint</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> randomNumber </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
        computerMove </span><span class="pun">=</span><span class="pln"> </span><span class="str">'r'</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'ROCK'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> randomNumber </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
        computerMove </span><span class="pun">=</span><span class="pln"> </span><span class="str">'p'</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'PAPER'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> randomNumber </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pun">:</span><span class="pln">
        computerMove </span><span class="pun">=</span><span class="pln"> </span><span class="str">'s'</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'SCISSORS'</span><span class="pun">)</span></pre>

<p>
	وهنا يظهر ما اختاره الحاسوب عشوائيًا.
</p>

<p>
	ولمّا كانت الدالة random.randint()‎ تعيد رقمًا عشوائيًا، فسنحتاج إلى تحويل الرقم الصحيح المخزن في المتغير <code>randomNumber</code> إلى حجرة أو ورقة أو مقص عبر البنية الشرطية <code>if</code> و <code>elif</code>، وبالتالي سيخزن البرنامج ما اختاره الحاسوب في المتغير <code>computerMove</code> ثم يطبع رسالة نصية فيها الحركة المختارة.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5380_102" style=""><span class="pln">    </span><span class="com"># عرض النتيجة الربح/الخسارة/التعادل</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> computerMove</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'It is a tie!'</span><span class="pun">)</span><span class="pln">
        ties </span><span class="pun">=</span><span class="pln"> ties </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'r'</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> computerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'s'</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You win!'</span><span class="pun">)</span><span class="pln">
        wins </span><span class="pun">=</span><span class="pln"> wins </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'p'</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> computerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'r'</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You win!'</span><span class="pun">)</span><span class="pln">
        wins </span><span class="pun">=</span><span class="pln"> wins </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'s'</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> computerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'p'</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You win!'</span><span class="pun">)</span><span class="pln">
        wins </span><span class="pun">=</span><span class="pln"> wins </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'r'</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> computerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'p'</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You lose!'</span><span class="pun">)</span><span class="pln">
        losses </span><span class="pun">=</span><span class="pln"> losses </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'p'</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> computerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'s'</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You lose!'</span><span class="pun">)</span><span class="pln">
        losses </span><span class="pun">=</span><span class="pln"> losses </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">elif</span><span class="pln"> playerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'s'</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> computerMove </span><span class="pun">==</span><span class="pln"> </span><span class="str">'r'</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You lose!'</span><span class="pun">)</span><span class="pln">
        losses </span><span class="pun">=</span><span class="pln"> losses </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span></pre>

<p>
	وفي النهاية، سيوازن البرنامج بين السلسلتين النصيتين الموجودتين في المتغيرين <code>playerMove</code> و <code>computerMove</code> ويظهر الناتج على الشاشة، وسيزيد قيمة أحد المتغيرات <code>wins</code> أو <code>losses</code> أو <code>ties</code> بما يناسب الحالة. بعد أن يصل تنفيذ البرنامج إلى النهاية فسيعود إلى بداية حلقة التكرار الرئيسية ونلعب دورًا جديدًا من اللعبة.
</p>

<h2 id="-14">
	الخلاصة
</h2>

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

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

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

<p>
	والآن هل تستطيع تجربة الآتي؟
</p>

<p>
	كتابة شيفرة تطبع Hello إذا كانت القيمة 1 مخزنة في المتغير <code>spam</code>، و World إذا كانت القيمة 2 في المتغير <code>spam</code>، و <code>Greetings</code> فيما عدا ذلك. كتابة برنامج قصير يطبع الأرقام من 1 إلى 10 باستخدام حلقة <code>for</code>. ثم اكتب برنامجًا مكافئًا له يطبع الأرقام من 1 إلى 10 باستخدام حلقة <code>while</code>.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://automatetheboringstuff.com/2e/chapter2/" rel="external nofollow">Flow Control</a> من كتاب <a href="https://automatetheboringstuff.com/#toc" rel="external nofollow">Automate the boring stuff with Python</a> لصاحبه Al Sweigart.
</p>

<h2 id="-15">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/python/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2325/" rel="">أساسيات لغة بايثون Python</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D9%85%D8%B5%D8%B7%D9%84%D8%AD%D8%A7%D8%AA-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1982/" rel="">مصطلحات بايثون البرمجية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/artificial-intelligence/%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-%D9%88%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1872/" rel="">أنواع البيانات والعمليات الأساسية في لغة بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/python/" rel="">تعلم لغة بايثون</a>
	</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>
</ul>
]]></description><guid isPermaLink="false">2335</guid><pubDate>Thu, 23 May 2024 16:00:00 +0000</pubDate></item><item><title>&#x623;&#x633;&#x627;&#x633;&#x64A;&#x627;&#x62A; &#x644;&#x63A;&#x629; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646; Python</title><link>https://academy.hsoub.com/programming/python/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2325/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_05/---(1).png.b0678adfce40bd0bc22dbd45e5b365f4.png" /></p>
<p>
	تمتلك لغة بايثون طيفًا واسعًا من البنى البرمجية، والدوال القياسية، وميزات رائعة لبيئات التطوير التفاعلية؛ لكن تجاهل أغلب ما ذكرته آنفًا وابدأ بتعلم ما تحتاج إليه لكتابة برامجك.
</p>

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

<p>
	في هذا المقال أمثلة عديدة أنصحك أن تكتبها في الصدفة التفاعلية التي تسمى أيضًا REPL (اختصار للعبارة Read-Evaluate-Print Loop أي حلقة قراءة-تقدير القيمة-طباعة)، التي تسمح لك بتنفيذ تعليمات بايثون كل تعليمة على حدة مباشرةً وتظهر لك الناتج.
</p>

<p>
	الصدفة التفاعلية رائعة لتتعلم التعليمات الأساسية في <a href="https://academy.hsoub.com/programming/python/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r211/" rel="">بايثون</a>، لذا أؤكد عليك أن تجربها أثناء قراءتك لهذا المقال وبالتالي ستتذكر المفاهيم المشروحة فيه تذكرًا أفضل لأنك تراها عمليًا أمامك بدل قراءتها فحسب.
</p>

<h2 id="">
	إدخال التعابير البرمجية في الصدفة التفاعلية
</h2>

<p>
	يمكنك تشغيل الصدفة التفاعلية بفتح محرر Mu، الذي يفترض أنك ثبتته وفق التعليمات في <a href="https://academy.hsoub.com/programming/python/%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2322/" rel="">المقال السابق</a>، افتح قائمة ابدأ في ويندوز أو مجلد التطبيقات في ماك وشغِّل محرر Mu، ثم اضغط على زر New ثم احفظ الملف الفارغ باسم مثل <code>blank.py</code>، وحينا تحاول تشغيل الملف باستخدام الزر Run أو الضغط على زر F5 في لوحة مفاتيحك فستفتح لك الصدفة التفاعلية في الجزء السفلي من نافذة المحرر، وسترى المحث <code>&lt;&lt;&lt;</code> أمامك.
</p>

<p>
	أدخل <code>2 + 2</code> في <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%A7-%D9%87%D9%88-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%9F-r353/" rel="">سطر الأوامر</a> لكي تجري عملية جمع بسيطة، يجب أن تبدو الطرفية التفاعلية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_9" style=""><span class="pun">&gt;&gt;&gt;</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">2</span><span class="pln">
</span><span class="lit">4</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span></pre>

<p>
	نسمي <code>2 + 2</code> في بايثون بالتعبير البرمجي expression، وهي أبسط أنواع التعليمات البرمجية في اللغة، وتتألف التعابير البرمجية عادةً من قيم (مثل 2) وعوامل (operators مثل <code>+</code>)، وتقدر قيمتها evaluate إلى قيمة واحدة؛ وهذا يعني أنك تستطيع استخدام التعابير في أي مكان في شيفرات <a href="https://wiki.hsoub.com/Python" rel="external">بايثون</a> تستطيع فيه استخدام قيمة ما.
</p>

<p>
	تقدر قيمة التعبير <code>2 + 2</code> في المثال السابق إلى قيمة واحدة هي 4، واعلم أن قيمةً واحدةً لا عامل فيها مثل 4 تُعَد تعبيرًا برمجيًا في بايثون أيضًا، كما هو واضح هنا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_11" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
</span><span class="lit">2</span></pre>

<h3 id="-1">
	لا ضير من الأخطاء
</h3>

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

<p>
	إذا أردت أن تتعرف على المزيد من المعلومات حول الخطأ الذي ظهر لك، فعليك البحث في الإنترنت عنه، أو العودة إلى <a href="https://wiki.hsoub.com/Python" rel="external">توثيق لغة بايثون</a>.
</p>

<p>
	يمكنك استخدام عوامل عديدة في تعابير بايثون، فالجدول الآتي يستعرض جميع <a href="https://academy.hsoub.com/programming/python/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%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%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-r730/" rel="">العوامل الحسابية في بايثون</a>.
</p>

<table>
	<thead>
		<tr>
			<th>
				العامل
			</th>
			<th>
				العملية
			</th>
			<th>
				مثال
			</th>
			<th>
				الناتج
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				**
			</td>
			<td>
				القوة (أو الأس)
			</td>
			<td>
				2‎ ** 3
			</td>
			<td>
				8
			</td>
		</tr>
		<tr>
			<td>
				%
			</td>
			<td>
				باقي القسمة
			</td>
			<td>
				22‎ % 8
			</td>
			<td>
				6
			</td>
		</tr>
		<tr>
			<td>
				//
			</td>
			<td>
				عامل قسمة الأعداد الصحيحة
			</td>
			<td>
				22‎ // 8
			</td>
			<td>
				2
			</td>
		</tr>
		<tr>
			<td>
				/
			</td>
			<td>
				القسمة
			</td>
			<td>
				22‎ / 8
			</td>
			<td>
				2.75
			</td>
		</tr>
		<tr>
			<td>
				*
			</td>
			<td>
				الضرب
			</td>
			<td>
				3‎ * 5
			</td>
			<td>
				15
			</td>
		</tr>
		<tr>
			<td>
				-
			</td>
			<td>
				الطرح
			</td>
			<td>
				5‎ - 2
			</td>
			<td>
				3
			</td>
		</tr>
		<tr>
			<td>
				+
			</td>
			<td>
				الجمع
			</td>
			<td>
				2 + 2
			</td>
			<td>
				4
			</td>
		</tr>
	</tbody>
</table>

<p style="text-align: center;">
	جدول العوامل الرياضية من أعلاها إلى أدناها أولوية وأسبقية
</p>

<p>
	ترتيب أولوية العمليات في بايثون (تسمى أيضًا «أسبقية») مشابهة لأولويتها في الرياضيات، فتقدر قيمة المعامل <code>**</code> أولًا، ثم تأتي المعاملات <code>*</code> و <code>/</code> و <code>//</code> و <code>%</code> بالترتيب حسب التعبير من اليسار إلى اليمين، ثم يأتي المعاملان <code>+</code> و <code>-</code> بالترتيب أيضًا من اليسار إلى اليمين. يمكنك استخدام الأقواس <code>()</code> لتغيير الترتيب إن احتجت إلى ذلك.
</p>

<p>
	لا تلعب المسافات الفارغة أي معنى بين العوامل في بايثون (عدا المسافة البادئة في أول السطر) لكن من المتعارف عليه استخدام فراغ واحد بينها. أدخل التعابير الآتية في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_14" style=""><span class="pun">&gt;&gt;&gt;</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">3</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">6</span><span class="pln">
</span><span class="lit">20</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="lit">2</span><span class="pln"> </span><span class="pun">+</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">6</span><span class="pln">
</span><span class="lit">30</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">48565878</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">578453</span><span class="pln">
</span><span class="lit">28093077826734</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</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">8</span><span class="pln">
</span><span class="lit">256</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">23</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">7</span><span class="pln">
</span><span class="lit">3.2857142857142856</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">23</span><span class="pln"> </span><span class="pun">//</span><span class="pln"> </span><span class="lit">7</span><span class="pln">
</span><span class="lit">3</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">23</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="lit">7</span><span class="pln">
</span><span class="lit">2</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</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">2</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="pun">(</span><span class="lit">5</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="pun">*</span><span class="pln"> </span><span class="pun">((</span><span class="lit">7</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="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="lit">3</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">16.0</span></pre>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="149547" href="https://academy.hsoub.com/uploads/monthly_2024_05/4-math-exporession.jpg.831de14ad67e8189b383bf99d57fb17e.jpg" rel=""><img alt="4 math exporession" class="ipsImage ipsImage_thumbnailed" data-fileid="149547" data-unique="du8ynb9x4" src="https://academy.hsoub.com/uploads/monthly_2024_05/4-math-exporession.jpg.831de14ad67e8189b383bf99d57fb17e.jpg"> </a>
</p>

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

<ul>
	<li>
		هذه الجملة صحيحة قاعديًا في اللغة العربية.
	</li>
	<li>
		جملة صحيحة في اللغة العربية قاعديًا.
	</li>
</ul>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_16" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">+</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;stdin&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pln">
    </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="typ">SyntaxError</span><span class="pun">:</span><span class="pln"> invalid syntax
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">42</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </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="lit">2</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;stdin&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pln">
    </span><span class="lit">42</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </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="lit">2</span><span class="pln">
             </span><span class="pun">^</span><span class="pln">
</span><span class="typ">SyntaxError</span><span class="pun">:</span><span class="pln"> invalid syntax</span></pre>

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

<h2 id="-2">
	أنواع البيانات العددية والعشرية والنصية
</h2>

<p>
	أذكرك أن التعابير هي قيم تجمعها المعاملات، وتكون نتيجتها هي قيمة واحدة دومًا.
</p>

<p>
	نوع البيانات data type هو تصنيف للقيم، فكل قيمة يكون لها نوع بيانات واحد فقط، وسنذكر في الجدول الآتي أكثر أنواع البيانات شيوعًا. القيمة ‎-2 و 30 هي أعداد صحيحة integer أو اختصارًا <code>int</code>، والتي تشير إلى أنها أعداد كاملة دون فواصل ويمكن أن تكون موجبة أو سالبة؛ أما الأرقام مع فاصلة عشرية مثل 3.14 فهي تسمى «الأرقام ذات الفاصلة العائمة» floating-point numbers أو اختصارًا <code>floats</code>. انتبه إلى أن القيمة 42 هي عدد صحيح <code>int</code>، بينما 42.0 هي قيمة ذات فاصلة عائمة float.
</p>

<table>
	<thead>
		<tr>
			<th>
				نوع البيانات
			</th>
			<th>
				أمثلة
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				أرقام صحيحة
			</td>
			<td>
				-2, -1, 0, 1, 2, 3, 4, 5
			</td>
		</tr>
		<tr>
			<td>
				أرقام ذات فاصلة عائمة
			</td>
			<td>
				-1.25, -1.0, -0.5, 0.0, 0.5, 1.0, 1.25
			</td>
		</tr>
		<tr>
			<td>
				سلاسل نصية
			</td>
			<td>
				'a', 'aa', 'aaa', 'Hello!', '11 cats'‎
			</td>
		</tr>
	</tbody>
</table>

<p style="text-align: center;">
	جدول أنواع البيانات الشائعة
</p>

<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="">بالسلاسل النصية strings</a> أو اختصارًا <code>strs</code>. احرص على إحاطة السلاسل النصية التي تضعها في برامج بعلامة اقتباس مفردة ' كما في 'مرحبًا' أو 'مع السلامة' لكي تعرف بايثون أين تبدأ السلسلة النصية وأين تنتهي. يمكنك أيضًا إنشاء سلاسل نصية فارغة بكتابة ''، سنتعلم السلاسل النصية تفصيليًا في مقال لاحق.
</p>

<p>
	إذا رأيت رسالة الخطأ SyntaxError: EOL while scanning string literal فمن المرجح أنك نسيت علامة الاقتباس المفردة في نهاية السلسلة النصية، كما في المثال الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_18" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello, world!
SyntaxError: EOL while scanning string literal</span></pre>

<h2 id="-3">
	ضم السلاسل النصية وتكرارها
</h2>

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

<pre class="ipsCode">&gt;&gt;&gt; 'Hello' + 'World'
'HelloWorld'
</pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_20" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello'</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">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#0&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="str">'Hello'</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">TypeError</span><span class="pun">:</span><span class="pln"> can only concatenate str </span><span class="pun">(</span><span class="kwd">not</span><span class="pln"> </span><span class="str">"int"</span><span class="pun">)</span><span class="pln"> to str</span></pre>

<p>
	رسالة الخطأ can only concatenate str (not "int") to str تعني أن بايثون تظن أنك تحاول ضم عدد صحيح 42 إلى سلسلة نصية 'Hello'، فإذا كنت تريد فعل ذلك فعليك أن تحول نوع البيانات العددي إلى نصي يدويًا لأن بايثون لن تفعل ذلك تلقائيًا بالنيابة عنك. سنتعلم تحويل أنواع البيانات في قسم «فهم مكونات تطبيقك الأول» حينما نتحدث عن الدوال str()‎ و int()‎ و float()‎.
</p>

<p>
	العامل <code>*</code> يضبط عددين صحيحين أو ذوي فاصلة عائلة مع بعضها بعضًا، لكن حين استخدامه مع سلسلة نصية وعدد صحيح فإنه يكرهها ويسمى عامل string replication. لترى كيف يعمل، أدخل سلسلةً نصية متبوعةً بعامل <code>*</code> ثم رقم في الصدفة الفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_22" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello'</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
</span><span class="str">'HelloHelloHelloHelloHello'</span></pre>

<p>
	نتيجة التعبير السابق هي قيمة نصية واحدة تُكرَّر فيها السلسلة النصية الأصلية عددًا محددًا من المرات قيمته هي قيمة العدد الصحيح. يفيدنا عامل تكرار السلاسل النصية في بعض الأحيان لكن فائدته لا تقارن بفائدة عامل الضم الذي نستعمله كثيرًا.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_24" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Hello'</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="str">'World'</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#32&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="str">'Hello'</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="str">'World'</span><span class="pln">
</span><span class="typ">TypeError</span><span class="pun">:</span><span class="pln"> can</span><span class="str">'t multiply sequence by non-int of type '</span><span class="pln">str</span><span class="str">'
&gt;&gt;&gt; '</span><span class="typ">Hello</span><span class="str">' * 5.0
Traceback (most recent call last):
  File "&lt;pyshell#33&gt;", line 1, in &lt;module&gt;
    '</span><span class="typ">Hello</span><span class="str">' * 5.0
TypeError: can'</span><span class="pln">t multiply sequence by non</span><span class="pun">-</span><span class="pln">int of type </span><span class="str">'float'</span></pre>

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

<h2 id="-4">
	تخزين القيم في متغيرات
</h2>

<p>
	المتغير variable هو ما يشبه الصندوق في <a href="https://academy.hsoub.com/apps/operating-systems/%D8%A7%D9%84%D8%B0%D8%A7%D9%83%D8%B1%D8%A9-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-r880/" rel="">ذاكرة الحاسوب</a> الذي يسمح لك بتخزين قيمة واحدة فيه، فإذا أردت تخزين قيمة ناتج أحد التعبيرات البرمجية في برنامجك لاستعمالها لاحقًا فخزنها في متغير.
</p>

<h3 id="-5">
	عبارات الإسناد
</h3>

<p>
	ستستخدم عبارة إسناد assignment statement لتخزين القيم في متغيرات، وتتألف عبارة الإسناد من اسم المتغير وعلامة المساواة (وتسمى أيضًا عامل الإسناد) والقيمة التي نرغب بتخزينها.
</p>

<p>
	إذا كتبت مثلًا عبارة الإسناد spam = 42 فهذا يعني أن المتغير الذي اسمه spam سيخزِّن القيمة 42 داخله.
</p>

<p>
	تخيل أن المتغير هو صندوق له لافتة أو اسم، يمكنك أن تضع القيم داخله كما في الشكل الآتي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="149548" href="https://academy.hsoub.com/uploads/monthly_2024_05/5-var-box.jpg.8acd3d179c48c214dc0ba883e1ff6497.jpg" rel=""><img alt="5 var box" class="ipsImage ipsImage_thumbnailed" data-fileid="149548" data-unique="3oasjc7qm" src="https://academy.hsoub.com/uploads/monthly_2024_05/5-var-box.jpg.8acd3d179c48c214dc0ba883e1ff6497.jpg"> </a>
</p>

<p style="text-align: center;">
	العبارة spam = 42 تخبر البرنامج أن «المتغير spam يحتوي الآن على القيم العددية 42 داخله».
</p>

<p>
	على سبيل المثال، أدخِل ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_26" style=""><span class="pun">➊</span><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="lit">40</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
   </span><span class="lit">40</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> eggs </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">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">+</span><span class="pln"> eggs
   </span><span class="lit">42</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">+</span><span class="pln"> eggs </span><span class="pun">+</span><span class="pln"> spam
   </span><span class="lit">82</span><span class="pln">
</span><span class="pun">➌</span><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> spam </span><span class="pun">+</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
   </span><span class="lit">42</span></pre>

<p>
	سيُهيِّئ المتغير intialize أو يُنشَأ في أول مرة تخزن فيه قيمة ➊، وبعد ذلك يمكنك استخدامه في التعابير البرمجية مع غيره من المتغيرات والقيم ➋، وحين إسناد قيمة جديدة إلى المتغير ➌ فستنسى القيمة القديمة، ولذها السب كان ناتج قيمة المتغير spam في نهاية البرنامج هو 42 بدلًا من 40، وهذا ما يسمى بإعادة كتابة قيمة المتغير overwrite.
</p>

<p>
	أدخل الشيفرة الآتية في الصدقة التفاعلية لتجربة إعادة الكتابة فوق سلسلة نصية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_28" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Hello'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="str">'Hello'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Goodbye'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="str">'Goodbye'</span></pre>

<p>
	وكما في الصندوق في الشكل الآتي، فإن الصندوق spam يخزن القيمة 'Hello' إلى أن تبدلها إلى 'Goodbye'.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="149549" href="https://academy.hsoub.com/uploads/monthly_2024_05/6-var-overwrite.jpg.122e1871228fc8ed60b18e7e93fbdb25.jpg" rel=""><img alt="6 var overwrite" class="ipsImage ipsImage_thumbnailed" data-fileid="149549" data-unique="bgq90y3i5" src="https://academy.hsoub.com/uploads/monthly_2024_05/6-var-overwrite.jpg.122e1871228fc8ed60b18e7e93fbdb25.jpg"> </a>
</p>

<p style="text-align: center;">
	تنسى القيمة القديمة حين إسناد قيمة جديدة إلى المتغير.
</p>

<h3 id="-6">
	أسماء المتغيرات
</h3>

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

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

<p>
	يمكنك أن تسمي متغيراتك بأي اسم طالما التزمت بالشروط الثلاثة الآتية:
</p>

<ul>
	<li>
		أن يكون كلمةً واحدةً دون فراغات.
	</li>
	<li>
		أن يستعمل الأرقام والأحرف والشرطة السفلية _ فقط.
	</li>
	<li>
		ألا يبدأ برقم.
	</li>
</ul>

<table>
	<thead>
		<tr>
			<th>
				أسماء متغيرات صالحة
			</th>
			<th>
				أسماء متغيرات غير صالحة
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				current_balance
			</td>
			<td>
				current-balance لا يسمح باستخدام الشرطات
			</td>
		</tr>
		<tr>
			<td>
				currentBalance
			</td>
			<td>
				current balance لا يسمح باستخدام الفراغات
			</td>
		</tr>
		<tr>
			<td>
				account4
			</td>
			<td>
				4account لا يمكن أن يبدأ برقم
			</td>
		</tr>
		<tr>
			<td>
				TOTAL_SUM
			</td>
			<td>
				TOTAL_$UM لا يسمح باستخدام المحارف الخاصة مثل $
			</td>
		</tr>
		<tr>
			<td>
				hello
			</td>
			<td>
				hello' لا يسمح باستخدام محارف خاصة مثل '
			</td>
		</tr>
	</tbody>
</table>

<p style="text-align: center;">
	جدول أسماء صالحة وغير صالحة للمتغيرات
</p>

<p>
	أسماء المتغيرات حساسة لحالة الأحرف، وهذا يعني أن spam و SPAM و Spam و sPaM هي أربعة متغيرات مختلفة، وصحيحٌ أن الاسم Spam صالح لتسمية المتغيرات في بايثون، لكن من المتعارف عليه أن نبدأ متغيراتنا بأحرف صغيرة.
</p>

<p>
	سنستخدم طريقة التسمية «سنام الجمل» camel case في أمثلة هذه السلسلة بدلًا من الشرطات السفلية، أي أن المتغيرات ستكون lookLikeThis بدلًا من look<em>like</em>this. قد يشير المبرمجون الخبراء إلى أن الدليل الرسمي لتنسيق شيفرات بايثون المسمى PEP 8 يقول أن علينا استخدام الشرطات السفلية، لكنني شخصيًا أفضل كتابة المتغيرات بطريقة سنام الجمل، وأقتبس من فقرة «A Foolish Consistency Is the Hobgoblin of Little Minds» في دليل PEP 8 نفسه:
</p>

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

	<p data-gramm="false">
		«من المهم التوافق مع دليل تنسيق الشيفرات، لكن أهم شيء هو معرفة متى يمكنك أن تختلف معه. فبعض الأحيان ليس من المناسب التوافق مع نمط التنسيق، واحكم بنفسك على تلك الحالات.»
	</p>
</blockquote>

<h2 id="-7">
	برنامجك الأول
</h2>

<p>
	صحيحٌ أن الصدفة التفاعلية جيدة لتكتب تعليمات بايثون كل واحدةً على حدة، لكن لكتابة برامج كاملة متكاملة فعليك أن تكتب التعليمات البرمجية في محرر شيفرات.
</p>

<p>
	محررات الشيفرات تشبه كثيرًا محررات النصوص العادية مثل المفكرة أو TextMate لكنها تحتوي على ميزات مخصصة لتسهيل كتابة الشيفرات البرمجية.
</p>

<p>
	ولفتح نافذة تحرير ملف جديد في محرر Mu، اضغط على زر New في الصف العلوي من النافذة.
</p>

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

<p>
	حان الوقت لكتابة أول برنامج لك! حينما تظهر لك نافذة المحرر أدخل فيها الأسطر الآتية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_30" style=""><span class="pun">➊</span><span class="pln"> </span><span class="com"># يرحب البرنامج بالمستخدم ويسأله عن عمره</span><span class="pln">

</span><span class="pun">➋</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hello, world!'</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'What is your name?'</span><span class="pun">)</span><span class="pln">    </span><span class="com"># اسأل عن الاسم</span><span class="pln">
</span><span class="pun">➌</span><span class="pln"> myName </span><span class="pun">=</span><span class="pln"> input</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="str">'It is good to meet you, '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> myName</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="str">'The length of your name is:'</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">len</span><span class="pun">(</span><span class="pln">myName</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="str">'What is your age?'</span><span class="pun">)</span><span class="pln">    </span><span class="com"># اسأل عن العمر</span><span class="pln">
   myAge </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
   </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You will be '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">int</span><span class="pun">(</span><span class="pln">myAge</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="pun">+</span><span class="pln"> </span><span class="str">' in a year.'</span><span class="pun">)</span></pre>

<p>
	بعد أن تدخل الشيفرة المصدرية السابقة فعليك حفظها لكي لا تكتبها كل مرة تشغل فيها محرر Mu. اضغط على زر Save واكتب اسم الملف <code>hello.py</code> ثم اضغط على Save لحفظه.
</p>

<p>
	أنصحك أن تحفظ برامجك التي تكتبها بين الحين والآخر أثناء كتابتها وتطويرها، فلو حدث خلل في حاسوبك أو أغلقت محرر الشيفرات خطأً فلن تخسر ما كتبته، ويمكنك استعمال اختصار الحفظ الذي هو <code>Ctrl+S</code> في ويندوز ولينكس و <code>‎⌘+S</code> في نظام ماك.
</p>

<p>
	بعد أن تحفظ الملف يمكنك تشغيل برنامجك. اضغط على زر F5 في لوحة المفاتيح ويجب أن يبدأ تشغيل البرنامج في الصدفة التفاعلية. تذكر أنك عليك الضغط على زر F5 من نافذة المحرر وليس من نافذة الصدفة التفاعلية.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_32" style=""><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> world</span><span class="pun">!</span><span class="pln">
</span><span class="typ">What</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> your name</span><span class="pun">?</span><span class="pln">
</span><span class="typ">Abdullatif</span><span class="pln">
</span><span class="typ">It</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> good to meet you</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Abdullatif</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> length of your name </span><span class="kwd">is</span><span class="pun">:</span><span class="pln">
</span><span class="lit">10</span><span class="pln">
</span><span class="typ">What</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> your age</span><span class="pun">?</span><span class="pln">
</span><span class="lit">5</span><span class="pln">
</span><span class="typ">You</span><span class="pln"> will be </span><span class="lit">6</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> a year</span><span class="pun">.</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></pre>

<p>
	عندما لا يبقى أي شيفرات لتنفَّذ فسينتهي برنامج بايثون terminate، أي أنه يتوقف عن العمل، ويمكننا القول بتعبير تقني أنه يخرج exit. يمكنك إغلاق محرر النصوص بالضغط على زر X في أعلى النافذة، ولإعادة فتح برنامج سابق اضغط على File ثم Open من القائمة العلوية، وستظهر نافذة اختيار الملفات التي ستختار منها الملف <code>hello.py</code> وتضغط على زر Open؛ يفترض أن ترى أمامك الملف <code>hello.py</code> الذي كتبته وحفظته سابقًا.
</p>

<h2 id="-8">
	فهم مكونات تطبيقك الأول
</h2>

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

<h3 id="-9">
	التعليقات
</h3>

<p>
	يسمى السطر الآتي تعليقًا comment:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_34" style=""><span class="pun">➊</span><span class="pln"> </span><span class="com"># يرحب البرنامج بالمستخدم ويسأله عن عمره</span></pre>

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

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

<h3 id="print">
	الدالة print()‎
</h3>

<p>
	تظهر الدالة <code>print()‎</code> قيمة السلسلة النصية الموجودة بين قوسين على الشاشة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_36" style=""><span class="pun">➋</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hello, world!'</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'What is your name?'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># اسأل عن الاسم</span></pre>

<p>
	السطر print('Hello, world!')‎ يعني «اطبع النص الموجود في السلسلة النصية ‎'Hello, world!'‎، فحين تنفيذ بايثون لهذا السطر فأنت تطلب منها أن تستدعي الدالة print()‎ وأن تمرِّر pass قيمة السلسلة النصية إلى تلك الدالة. القيمة التي تمرر إلى استدعاء دالة function call تسمى بالوسيط argument. لاحظ أن علامات الاقتباس لا تظهر على الشاشة، فهي إشارة متى تبدأ وتنتهي السلسلة النصية، وليست جزءًا من النص.
</p>

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

	<p data-gramm="false">
		ملاحظة: يمكنك أن تستخدم هذه الدالة لتطبع سطرًا فارغًا على الشاشة؛ فكل ما عليك فعله هو استدعاء print()‎ دون أي شيء بين قوسين. حينما تكتب اسم الدالة ويليه قوسَي الفتح والإغلاق فأنت تستدعي دالةً اسمها هو الاسم الذي يسبق القوسين. سنشرح الدوال تفصيليًا مقال لاحق.
	</p>
</blockquote>

<h3 id="input">
	الدالة input()‎
</h3>

<p>
	تنتظر الدالة input()‎ أن يدخل المستخدم نصًا عبر لوحة المفاتيح ثم يضغط على زر Enter:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_38" style=""><span class="pun">➌</span><span class="pln"> myName </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span></pre>

<p>
	نتيجة استدعاء هذه الدالة هي سلسلة نصية تطابق ما أدخله المستخدم، ثم ستُسند السلسلة النصية الناتجة عن هذا الاستدعاء إلى المتغير myName. يمكنك أن تعدّ عملية استدعاء الدالة input()‎ على أنها تعبير برمجي نتيجته هي قيمة السلسلة النصية التي أدخلها المستخدم، فإذا أدخل المستخدم 'Ahmed' فيمكنك أن تقول أن التعبير البرمجي أصبح أشبه بالتعبير myName = 'Ahmed'‎.
</p>

<p>
	إذا استدعيت الدالة input()‎ وظهرت لك رسالة خطأ مثل NameError: name 'Ahmed' is not defined، فهذا يعني أنك تشغل الشيفرة عبر الإصدار الثاني من بايثون وليس الثالث.
</p>

<h3 id="-10">
	طباعة اسم المستخدم
</h3>

<p>
	يحتوي الاستدعاء التالي للدالة print()‎ على التعبير ‎'It is good to meet you, ' + myName بين القوسين:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_40" style=""><span class="pun">➍</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'It is good to meet you, '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> myName</span><span class="pun">)</span></pre>

<p>
	تذكر أن بايثون تقدر قيمة التعابير البرمجية وتنتهي بقيمة واحدة. فإذا احتوى المتغير myName على القيمة 'Ahmed' في السطر ➌، فستقدر قيمة التعبير السابق إلى 'It is good to meet you, Ahmed'، ثم ستمرر هذه السلسلة النصية إلى الدالة print()‎ التي تطبعها على الشاشة.
</p>

<h3 id="len">
	الدالة len()‎
</h3>

<p>
	يمكنك أن تمرر سلسلةً نصيةً إلى الدالة len()‎ أو متغيرًا يحتوي على سلسلةٍ نصية، وستنتج الدالة عددًا صحيحًا يمثل عدد المحارف في السلسلة النصية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_42" style=""><span class="pun">➎</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'The length of your name is:'</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">len</span><span class="pun">(</span><span class="pln">myName</span><span class="pun">))</span></pre>

<p>
	أجرب إدخال ما يلي إلى الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_44" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> len</span><span class="pun">(</span><span class="str">'hello'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">5</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> len</span><span class="pun">(</span><span class="str">'I like to drink good coffee'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">27</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> len</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
</span><span class="lit">0</span></pre>

<p>
	وكما في الأمثلة السابقة، ستكون نتيجة len(myName)‎ هي رقم صحيح، ثم ستمرر إلى الدالة print()‎ لطباعتها. تذكر أن الدالة print()‎ تسمح لك بطباعة أعداد أو سلاسل نصية، لكن لاحظ رسالة الخطأ التي تظهر حينما تحاول كتابة ما يلي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_46" style=""><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="str">'I am '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">29</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">' years old.'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#6&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'I am '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">29</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">' years old.'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">TypeError</span><span class="pun">:</span><span class="pln"> can only concatenate str </span><span class="pun">(</span><span class="kwd">not</span><span class="pln"> </span><span class="str">"int"</span><span class="pun">)</span><span class="pln"> to str</span></pre>

<p>
	لا يأتي الخطأ من دالة print()‎ بل من التعبير الذي حاولت تمريره إلى الدالة، وستحصل على رسالة الخطأ نفسها إذا كتبت التعبير البرمجي بمفرده في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_48" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'I am '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">29</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">' years old.'</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#7&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="str">'I am '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">29</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">' years old.'</span><span class="pln">
</span><span class="typ">TypeError</span><span class="pun">:</span><span class="pln"> can only concatenate str </span><span class="pun">(</span><span class="kwd">not</span><span class="pln"> </span><span class="str">"int"</span><span class="pun">)</span><span class="pln"> to str</span></pre>

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

<h3 id="strintfloat">
	الدوال str()‎ و int()‎ و float()‎
</h3>

<p>
	إذا أردت ضم عدد صحيح مثل 29 إلى سلسلة نصية لتمريره إلى الدالة print()‎ مثلًا، فما ستحتاج إليه هو السلسلة النصية '29' التي هي النسخة النصية من العدد 29.
</p>

<p>
	الدالة str()‎ تقبل أن يُمرَّر إليها عدد صحيح ثم تنتج لنا سلسلةً نصيةً تمثل هذا العدد كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_50" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> str</span><span class="pun">(</span><span class="lit">29</span><span class="pun">)</span><span class="pln">
</span><span class="str">'29'</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="str">'I am '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="lit">29</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">' years old.'</span><span class="pun">)</span><span class="pln">
I am </span><span class="lit">29</span><span class="pln"> years old</span><span class="pun">.</span></pre>

<p>
	ولأن ناتج التعبير str(29)‎ هو '29' فسيكون ناتج التعبير ‎'I am ' + str(29) + ' years old.'‎ هو ‎'I am ' + '29' + ' years old.'‎ الذي بدوره سينتج ‎'I am 29 years old.'‎، وهذه هي القيمة التي ستمرر إلى الدالة print()‎.
</p>

<p>
	الدوال str()‎ و int()‎ و float()‎ ستحول القيم التي تمررها إليها إلى سلسلة نصية وعدد صحيح وعدد ذي فاصلة عائلة على التوالي وبالترتيب. جرب تحول بعض القيم في الصدفة التفاعلية وانظر ماذا سيحدث:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_52" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> str</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
</span><span class="str">'0'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> str</span><span class="pun">(-</span><span class="lit">3.14</span><span class="pun">)</span><span class="pln">
</span><span class="str">'-3.14'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> int</span><span class="pun">(</span><span class="str">'42'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">42</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> int</span><span class="pun">(</span><span class="str">'-99'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">-</span><span class="lit">99</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> int</span><span class="pun">(</span><span class="lit">1.25</span><span class="pun">)</span><span class="pln">
</span><span class="lit">1</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> int</span><span class="pun">(</span><span class="lit">1.99</span><span class="pun">)</span><span class="pln">
</span><span class="lit">1</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> float</span><span class="pun">(</span><span class="str">'3.14'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">3.14</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> float</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span><span class="pln">
</span><span class="lit">10.0</span></pre>

<p>
	نستدعي في المثال السابق الدوال str()‎ و int()‎ و float()‎ ونمرر إليهم مجموعةً من القيم لها أنواع بيانات مختلفة، وسنحصل على نسخة نصية أو عددية من تلك القيم.
</p>

<p>
	تفيد الدالة str()‎ حينما يكون لدينا عدد صحيح أو ذو فاصلة عائمة ونريد ضمه إلى سلسلة نصية، بينما تفيد الدالة int()‎ حينما يكون لدينا رقم مخزن على شكل سلسلة نصية ونريد إجراء بعض العمليات الحسابية عليه، فمثلًا تعيد الدالة input()‎ سلسلةً نصيةً دومًا حتى لو أدخل المستخدم رقمًا، فجرب إدخال spam = input()‎ في الصدفة التفاعلية وكتابة رقم ما ثم طباعة قيمة المتغير spam:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_54" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
</span><span class="lit">101</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="str">'101'</span></pre>

<p>
	لاحظ أن القيمة المخزنة في المتغير spam ليست العدد 101 بل السلسلة النصية '101'، فلو أردت إجراء أي عملية رياضية على القيمة المخزنة في spam فعليك استخدام الدالة int()‎ للحصول على عدد صحيح. سنعيد تخزين القيمة العددية للمتغير spam في المتغير spam نفسه:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_56" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">=</span><span class="pln"> int</span><span class="pun">(</span><span class="pln">spam</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam
</span><span class="lit">101</span></pre>

<p>
	يمكنك الآن التعامل مع المتغير spam كأي عدد صحيح:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_58" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> spam </span><span class="pun">*</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
</span><span class="lit">202.0</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_60" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> int</span><span class="pun">(</span><span class="str">'99.99'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#18&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    int</span><span class="pun">(</span><span class="str">'99.99'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">ValueError</span><span class="pun">:</span><span class="pln"> invalid literal </span><span class="kwd">for</span><span class="pln"> int</span><span class="pun">()</span><span class="pln"> </span><span class="kwd">with</span><span class="pln"> base </span><span class="lit">10</span><span class="pun">:</span><span class="pln"> </span><span class="str">'99.99'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> int</span><span class="pun">(</span><span class="str">'twelve'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#19&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    int</span><span class="pun">(</span><span class="str">'twelve'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">ValueError</span><span class="pun">:</span><span class="pln"> invalid literal </span><span class="kwd">for</span><span class="pln"> int</span><span class="pun">()</span><span class="pln"> </span><span class="kwd">with</span><span class="pln"> base </span><span class="lit">10</span><span class="pun">:</span><span class="pln"> </span><span class="str">'twelve'</span></pre>

<p>
	تفيد أيضًا الدالة int()‎ بتحويل عدد عشري إلى عدد صحيح (مع تقريبه إلى أصغر عدد صحيح يمثله):
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_62" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> int</span><span class="pun">(</span><span class="lit">7.7</span><span class="pun">)</span><span class="pln">
</span><span class="lit">7</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> int</span><span class="pun">(</span><span class="lit">7.7</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">8</span></pre>

<p>
	لقد استخدمنا الدالتين int()‎ و str()‎ في آخر ثلاثة أسطر من برنامجك للحصول على قيمة نوع البيانات المطلوب:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_64" style=""><span class="pun">➏</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'What is your age?'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># ask for their age</span><span class="pln">
   myAge </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
   </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'You will be '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">int</span><span class="pun">(</span><span class="pln">myAge</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="pun">+</span><span class="pln"> </span><span class="str">' in a year.'</span><span class="pun">)</span></pre>

<h3 id="-11">
	مساواة النصوص والأرقام
</h3>

<p>
	صحيحٌ أن القيمة النصية لعددٍ ما تختلف اختلافًا تامًا عن العدد الصحيح أو العدد ذي الفاصلة العائمة، لكن يمكن أن يساوي العددُ الصحيح العددَ ذا الفاصلة العائمة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_66" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">42</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">'42'</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">42</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">42.0</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">42.0</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0042.000</span><span class="pln">
</span><span class="kwd">True</span></pre>

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

<p>
	المتغير myAge يحتوي على القيمة المعادة من input()‎، ولمّا كانت القيمة المعادة من الدالة input()‎ هي سلسلة نصية دومًا حتى لو أدخل المستخدم رقمًا، فعلينا استخدام int(myAge)‎ لإعادة قيمة عددية صحيحة من السلسلة النصية الموجودة في myAge، ثم سنزيد مقدار هذا العدد بواحد في التعبير int(myAge) +1.
</p>

<p>
	سنمرر بعد ذلك نتيجة التعبير السابق إلى الدالة str()‎ على الشكل str(int(myAge) +1)‎، ثم سنضم القيمة النصية للتعبير السابق مع السلسلتين النصيتين ‎'You will be '‎ و ‎' in a year.'‎ وذلك للحصول على قيمة نصية واحدة، ثم ستمرر هذه القيمة النصية إلى الدالة print()‎ لطباعتها على الشاشة.
</p>

<p>
	لنقل مثلًا أن المستخدم أدخل السلسلة النصية '4' قيمةً للمتغير myAge عبر الدالة input()‎. ستحول السلسلة النصية '4' إلى عدد صحيح 4، ثم سيضاف 1 إليها فتصبح 5، ثم تحولها الدالة str()‎ إلى سلسلة نصية مجددًا لإضافتها إلى السلاسل النصية الأخرى، وبالتالي ستنتج لدينا النسخة النهائية التي ستطبع على الشاشة، كما هو ظاهر في الشكل الآتي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="149550" href="https://academy.hsoub.com/uploads/monthly_2024_05/7-print-str-int.jpg.2d3bf1e5d04675df6d375da1e4ee5dc7.jpg" rel=""><img alt="7 print str int" class="ipsImage ipsImage_thumbnailed" data-fileid="149550" data-unique="g6ly70f95" src="https://academy.hsoub.com/uploads/monthly_2024_05/7-print-str-int.jpg.2d3bf1e5d04675df6d375da1e4ee5dc7.jpg"> </a>
</p>

<h2 id="-12">
	الخلاصة
</h2>

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

<p>
	من المهم أن تتذكر من هذا المقال أنواع العوامل المختلفة (+ و - و * و / و // و % و ** للعوامل الحسابية، و + و * للسلاسل النصية) وأنواع البيانات المختلفة (الأعداد الصحيحة integers والأعداد ذات الفاصلة العائمة floating-point والسلاسل النصية string).
</p>

<p>
	شرحنا أيضًا بعض الدوال، مثل print()‎ و input()‎ التي تتعامل مع النصوص البسيطة لطباعتها على الشاشة أو لإدخالها من لوحة المفاتيح، واستعملنا الدالة len()‎ للحصول على القيمة العددية لسلسلة نصية، وساعدتنا الدوال str()‎ و int()‎ و float()‎ في تحويل القيم المُمرَّرة إليها إلى سلاسل نصية أو أعداد صحيحة أو أعداد ذات فاصلة على التوالي.
</p>

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

<p>
	الآن وبعد أن أخذت المعارف اللازمة من المقال، برأيك لماذا سيسبب التعبير الآتي خطأً؟ وكيف نحله؟ شاركنا ذلك في التعليقات.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1937_68" style=""><span class="str">'I have eaten '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">99</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">' burritos.'</span></pre>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://automatetheboringstuff.com/2e/chapter1/" rel="external nofollow">Python Basics</a> من كتاب <a href="https://automatetheboringstuff.com/#toc" rel="external nofollow">Automate the boring stuff with Python</a> لصاحبه Al Sweigart.
</p>

<h2 id="-13">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/python/%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2322/" rel="">تهيئة بيئة العمل في بايثون Python</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%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-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1815/" rel="">أساسيات البرمجة بلغة بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/python/" rel="">تعلم لغة بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D9%85%D8%B4%D8%A7%D8%B1%D9%8A%D8%B9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D9%86%D8%A7%D8%B3%D8%A8-%D8%A7%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86-r2185/" rel="">مشاريع بايثون عملية تناسب المبتدئين</a>
	</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>
</ul>
]]></description><guid isPermaLink="false">2325</guid><pubDate>Wed, 08 May 2024 16:00:00 +0000</pubDate></item><item><title>&#x62A;&#x647;&#x64A;&#x626;&#x629; &#x628;&#x64A;&#x626;&#x629; &#x627;&#x644;&#x639;&#x645;&#x644; &#x641;&#x64A; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646; Python</title><link>https://academy.hsoub.com/programming/python/%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-r2322/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_05/-----.png.b960edc7852cb6224e5982e77d08a1d1.png" /></p>
<p>
	قبل شرح كيفية تهيئة بايثون، نود إعلامك أن هذا سيكون أول مقال من سلسلة مقالات أتمتة المهام عبر بايثون. ستشرح هذه السلسلة <a href="https://academy.hsoub.com/programming/python/%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-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1815/" rel="">أساسيات البرمجة بلغة بايثون</a>، والمهام المختلفة التي يمكن لحاسوبك أتمتتها، كما سنشاركك مشاريع عملية مع نهاية كل جزئية منه، والتي تستطيع استعمالها ودراستها ومشاركتنا تطبيقاتك لها في التعليقات.
</p>

<h2 id="">
	ما هي بايثون؟
</h2>

<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>، ولغة البرمجة هي مجموعة قواعد لكتابة الشيفرة يجب الالتزام بها ليفهمها مترجم اللغة، ومترجم بايثون Python interpreter هو برمجية تقرأ الشيفرات المصدرية بلغة بايثون وتطبق التعليمات البرمجية فيها.
</p>

<p>
	يمكنك أن تنزل مفسر لغة بايثون مجانًا من <a href="http://python.org" rel="external nofollow">موقع اللغة الرسمي</a>، الذي فيه إصدارات لأنظمة تشغيل ويندوز وماك ولينكس. إذا كنتَ تتساءل من أين أتى اسم بايثون، فهو من مجموعة كوميدية بريطانية اسمها Monty Python، ولا علاقة للثعابين والأفاعي باسمها.
</p>

<h2 id="-1">
	تنزيل وتثبيت بايثون
</h2>

<p>
	يمكنك تنزيل بايثون لنظام تشغيل ويندوز أو ماك أو <a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%86%D8%B8%D8%A7%D9%85-%D9%84%D9%8A%D9%86%D9%83%D8%B3-linux-%D9%88%D8%A3%D8%A8%D8%B1%D8%B2-%D9%85%D9%85%D9%8A%D8%B2%D8%A7%D8%AA%D9%87-%D9%88%D8%B9%D9%8A%D9%88%D8%A8%D9%87-r2252/" rel="">لينكس</a> مجانًا من <a href="https://www.python.org/downloads" rel="external nofollow">رابط موقع اللغة</a>، وستعمل معك جميع التطبيقات المشروحة في هذه السلسلة معك.
</p>

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

	<div class="ipsQuote_contents ipsClearfix" data-gramm="false">
		<p>
			<strong>تحذير</strong>: احرص على تنزيل النسخة الثالثة من بايثون (مثل 3.10.4) فالبرامج المشروحة في هذه السلسلة مكتوبة لتعمل على بايثون 3 ولن تعمل كما يجب على بايثون 2.
		</p>
	</div>
</blockquote>

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

<p>
	إذا كنت تستعمل نظام ويندوز فنزِّل مثبت بايثون (الذي ينتهي باللاحقة ‎.exe) وشغِّله، ثم اتبع ما يرشدك إليه المثبِّت على الشاشة. أما على نظام macOS فنزِّل ملف ‎.pkg ثم شغله واتبع الإرشادات الموجودة على الشاشة.
</p>

<p>
	أما إذا كنت تستعمل توزيعة أوبنتو (أو ما يشبهها من التوزيعات المبنية على دبيان) فيمكنك تثبيت بايثون من <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%A7-%D9%87%D9%88-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%9F-r353/" rel="">سطر الأوامر</a> بتنفيذ الأمر الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8307_13" style=""><span class="pln">sudo apt install python3 python3</span><span class="pun">-</span><span class="pln">pip idle3</span></pre>

<h2 id="mu">
	تنزيل وتثبيت محرر Mu
</h2>

<p>
	صحيحٌ أن مفسِّر بايثون هو البرنامج الذي يشغل شيفرات بايثون التي تكتبها، لكن برمجية Mu editor هي مكان إدخالك للشيفرات، بنفس الطريقة التي تكتب فيها بمعالج النصوص المفضل لديك. يمكنك <a href="https://codewith.mu" rel="external nofollow">تنزيل محرر Mu من موقعه</a>.
</p>

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

<h3 id="mu-1">
	تشغيل محرر Mu
</h3>

<p>
	بعد انتهاء تثبيت Mu، يمكنك تشغيله:
</p>

<ul>
	<li>
		في نظام ويندوز بالضغط على قائمة ابدأ ثم البحث عن Mu.
	</li>
	<li>
		في نظام MacOS بفتح Finder ثم Applications ثم الضغط على أيقونة mu-editor.
	</li>
	<li>
		في لينكس عليك تشغيل الطرفية Terminal ثم كتابة mu-editor.
	</li>
</ul>

<p>
	وحين تشغيلك لمحرر Mu لأول مرة فستظهر لك نافذة تخيّرك بين عدة خيارات وعليك اختيار Python 3، يمكنك في أي وقت تغيير النمط بالضغط على زر Mode في أعلى نافذة المحرر.
</p>

<h2 id="idle">
	تشغيل IDLE
</h2>

<p>
	نستعمل في هذه السلسلة Mu كمحرر وصدفة تفاعلية interactive shell، لكنك تستطيع استخدام أي محرر تشاء لكتابة شيفرات بايثون، وتثبت بيئة التطوير والتعليم المدمجة Integrated Development and Learning Environment ‏(اختصارًا IDLE) مع بايثون تلقائيًا، ويمكنها أن تعمل كمحرر ثانوي لك إن لم يعمل يثبت عندك محرر Mu. لنشغل IDLE:
</p>

<ul>
	<li>
		في نظام ويندوز بالضغط على قائمة ابدأ ثم البحث عن IDLE.
	</li>
	<li>
		في نظام macOS بفتح Finder ثم Applications ثم الضغط على أيقونة Python.
	</li>
	<li>
		في لينكس عليك تشغيل الطرفية Terminal ثم كتابة idle3.
	</li>
</ul>

<h2 id="interactiveshell">
	الصَدَفة التفاعلية Interactive Shell
</h2>

<p>
	عندما تشغل Mu فستظهر أمامك نافذة تحرير الملف، ويمكنك فتح الصَدَفة التفاعلية بالضغط على زر REPL.
</p>

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

<p>
	تجد الصدفة التفاعلية في محرر Mu في إطار في الجزء السفلي من النافذة فيها النص الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8307_17" style=""><span class="typ">Jupyter</span><span class="pln"> </span><span class="typ">QtConsole</span><span class="pln"> </span><span class="lit">4.7</span><span class="pun">.</span><span class="lit">7</span><span class="pln">
</span><span class="typ">Python</span><span class="pln"> </span><span class="lit">3.6</span><span class="pun">.</span><span class="lit">9</span><span class="pln"> </span><span class="pun">(</span><span class="pln">default</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Mar</span><span class="pln"> </span><span class="lit">15</span><span class="pln"> </span><span class="lit">2022</span><span class="pun">,</span><span class="pln"> </span><span class="lit">13</span><span class="pun">:</span><span class="lit">55</span><span class="pun">:</span><span class="lit">28</span><span class="pun">)</span><span class="pln"> 
</span><span class="typ">Type</span><span class="pln"> </span><span class="str">'copyright'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'credits'</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="str">'license'</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> more information
</span><span class="typ">IPython</span><span class="pln"> </span><span class="lit">7.16</span><span class="pun">.</span><span class="lit">3</span><span class="pln"> </span><span class="pun">--</span><span class="pln"> </span><span class="typ">An</span><span class="pln"> enhanced </span><span class="typ">Interactive</span><span class="pln"> </span><span class="typ">Python</span><span class="pun">.</span><span class="pln"> </span><span class="typ">Type</span><span class="pln"> </span><span class="str">'?'</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> help</span><span class="pun">.</span><span class="pln">

</span><span class="typ">In</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">]:</span><span class="pln"> </span></pre>

<p>
	إذا كنت تستعمل IDLE، فالصدفة التفاعلية هي أول ما ستراه أمامك، ويفترض أن تكون فارغة باستثناء نص يبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8307_19" style=""><span class="typ">Python</span><span class="pln"> </span><span class="lit">3.6</span><span class="pun">.</span><span class="lit">9</span><span class="pln"> </span><span class="pun">(</span><span class="pln">default</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Mar</span><span class="pln"> </span><span class="lit">15</span><span class="pln"> </span><span class="lit">2022</span><span class="pun">,</span><span class="pln"> </span><span class="lit">13</span><span class="pun">:</span><span class="lit">55</span><span class="pun">:</span><span class="lit">28</span><span class="pun">)</span><span class="pln"> 
</span><span class="pun">[</span><span class="pln">GCC </span><span class="lit">8.4</span><span class="pun">.</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> on linux
</span><span class="typ">Type</span><span class="pln"> </span><span class="str">"help"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"copyright"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"credits"</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="str">"license()"</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> more information</span><span class="pun">.</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></pre>

<p>
	الأسطر التي تبدأ بالعبارة In [1]:<code>‎</code> أو ‎<code>&lt;&lt;&lt;</code> تسمى محثًا prompt (أي أنها عبارة «تحثّ» المستخدم على كتابة أمر وراءها). أمثلة هذه السلسلة ستستخدم <code>&lt;&lt;&lt;</code> للإشارة إلى محث الصدفة التفاعلية لأنه أكثر شيوعًا. إذا شغلت مفسر بايثون من سطر الأوامر فستجد أمامك المحث <code>&lt;&lt;&lt;</code> أيضًا. يستخدم محرر Jupyter Notebook الشهير المحث <code>‎</code>In [1]:‎ وشاع بسببه.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8307_21" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hello, world!'</span><span class="pun">)</span></pre>

<p>
	بعد كتابة السطر السابق فاضغط على زر Enter، ويجب أن يظهر ما يلي في الصدفة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8307_23" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'Hello, world!'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> world</span><span class="pun">!</span></pre>

<p>
	لقد أعطيت الحاسوب أمرًا ونفذه لك. مبارك!
</p>

<h2 id="-">
	تثبيت الوحدات الخارجية في بايثون
</h2>

<p>
	كتب العديد من المطورين وحداتهم الخاصة، مما أدى إلى توسيع قدرات لغة بايثون Python إلى ما هو أبعد مما توفره المكتبة المعيارية للوحدات المُدمَجة مع بايثون، والطريقة الأساسية لتثبيت هذه الوحدات الخارجية هي استخدام الأداة Pip في بايثون، حيث تنزِّل هذه الأداة وحدات بايثون وتثبّتها بطريقة آمنة على حاسوبك من <a href="https://pypi.org/" rel="external nofollow">موقع الويب الخاص بمؤسسة برمجيات بايثون</a>، ويُعَد PyPI أو Python Package Index متجر التطبيقات المجاني لوحدات بايثون.
</p>

<p>
	<strong>ملاحظة</strong>: يمكنك تثبيت جميع الوحدات المطلوبة مع الإصدارات المستخدمة في هذه السلسلة من المقالات من خلال تثبيت الوحدة <code>automateboringstuff</code> باستخدام الأداة Pip، لذا شغّل الأمر ا<code>لآتي </code>من موجّه الأوامر أو نافذة الطرفية Terminal.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_50" style=""><span class="pln">pip install </span><span class="pun">--</span><span class="pln">user automateboringstuff </span></pre>

<h3 id="-pip">
	الأداة Pip
</h3>

<p>
	تُثبَّت الأداة Pip تلقائيًا مع الإصدار 3.4 من بايثون والإصدارات الأحدث على نظامي تشغيل ويندوز Windows وماك macOS، ولكن يجب أن تثبّتها تثبيتًا منفصلًا على نظام لينكس Linux. يمكنك معرفة ما إذا كانت الأداة Pip مُثبَّتة مسبقًا على نظام لينكس من خلال تشغيل الأمر <code>which pip3</code> في نافذة الطرفية Terminal، حيث إذا كانت مثبَّتة، فسترى موقع الأداة pip3 معروضًا، وإلّا فلن يُعرض أيّ شيء. يمكنك تثبيت الأداة pip3 على نظام أوبنتو Ubuntu أو نظام دبيان Debian Linux من خلال فتح نافذة طرفية جديدة وإدخال الأمر <code>sudo apt install python3-pip</code>، ويمكنك تثبيت الأداة pip3 على نظام فيدورا لينكس Fedora Linux من خلال إدخال الأمر <code>sudo dnf install python3-pip</code> في نافذة الطرفية، ويجب أن تدخِل كلمة مرور المدير الخاصة بحاسوبك.
</p>

<p>
	تُشغَّل الأداة pip من نافذة الطرفية (وتُسمَّى أيضًا سطر الأوامر)، وليس من صدفة بايثون التفاعلية Interactive Shell. شغّل برنامج "موجّه الأوامر Command Prompt" من قائمة "ابدأ Start" في نظام تشغيل ويندوز، وشغّل الطرفية من أيقونة سبوت لايت Spotlight على نظام ماك macOS، وشغّل الطرفية من أيقونة Ubuntu Dash أو اضغط على الاختصار Ctrl-Alt-T في نظام أوبنتو لينكس Ubuntu Linux.
</p>

<p>
	إن لم يكن مجلد pip موجودًا في متغير البيئة <code>PATH</code>، فيجب تغيير المجلد في نافذة الطرفية باستخدام الأمر <code>cd</code> قبل تشغيل الأداة pip. إذا أردتَ معرفة اسم المستخدم الخاص بك، فشغّل الأمر <code>echo %USERNAME%‎</code> على نظام ويندوز أو الأمر <code>whoami</code> على نظامي ماك macOS ولينكس، ثم شغّل الأمر <code>cd pip folder</code>، حيث يكون مجلد pip على نظام ويندوز في الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_56" style=""><span class="pln"> C</span><span class="pun">:</span><span class="pln">\Users\&lt;USERNAME</span><span class="pun">&gt;</span><span class="pln">\AppData\Local\Programs\Python\Python39\Scripts</span></pre>

<p>
	ويوجد هذا المجلد في نظام ماك macOS على:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_54" style=""><span class="pln"> </span><span class="pun">/</span><span class="typ">Library</span><span class="pun">/</span><span class="typ">Frameworks</span><span class="pun">/</span><span class="typ">Python</span><span class="pun">.</span><span class="pln">framework</span><span class="pun">/</span><span class="typ">Versions</span><span class="pun">/</span><span class="lit">3.9</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln"> </span></pre>

<p>
	كما يوجد هذا المجلد في نظام لينكس على:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_52" style=""><span class="pun">/</span><span class="pln">home</span><span class="pun">/&lt;</span><span class="pln">USERNAME</span><span class="pun">&gt;/.</span><span class="pln">local</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span></pre>

<p>
	، وبذلك ستكون في المجلد الصحيح لتشغيل الأداة pip.
</p>

<h3 id="-">
	تثبيت الوحدات الخارجية
</h3>

<p>
	يُسمَّى الملف القابل للتنفيذ للأداة pip بالاسم pip على نظام ويندوز ويسمّى pip3 على نظامي ماك macOS ولينكس. مرّر الأمر <code>install</code> متبوعًا باسم الوحدة التي تريد تثبيتها من سطر الأوامر، فمثلًا يمكنك إدخال الأمر <code>pip install --user MODULE</code> في نظام ويندوز، حيث <code>MODULE</code> هو اسم الوحدة.
</p>

<p>
	قد تكون التغييرات المستقبلية على هذه الوحدات الخارجية غير متوافقة مع الإصدارات السابقة، لذا نوصي بتثبيت الإصدارات المحدَّدة المستخدمة في هذه السلسلة من المقالات كما سنوضّح لاحقًا، حيث يمكنك إضافة الخيار <code>‎-U MODULE==VERSION</code> إلى نهاية اسم الوحدة لتثبيت إصدار محدّد، ولاحظ وجود إشارتي مساواة في خيار سطر الأوامر، فمثلًا يثبّت الأمر الآتي الإصدار 1.5.0 من الوحدة <code>send2trash</code><span>:</span>
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6326_6" style=""><span class="pln"> pip install </span><span class="pun">--</span><span class="pln">user </span><span class="pun">-</span><span class="pln">U send2trash</span><span class="pun">==</span><span class="lit">1.5</span><span class="pun">.</span><span class="lit">0</span><span class="pln"> </span></pre>

<p>
	يمكنك تثبيت جميع الوحدات التي تغطيها هذه السلسلة من المقالات من خلال تنزيل ملفات المتطلبات "requirements" لنظام تشغيلك من موقع <a href="https://nostarch.com/automatestuff2/" rel="external nofollow">nostarch</a> وتشغيل أحد الأوامر التالية:
</p>

<p>
	على نظام ويندوز:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_6" style=""><span class="pln">pip install </span><span class="pun">--</span><span class="pln">user </span><span class="pun">–</span><span class="pln">r automate</span><span class="pun">-</span><span class="pln">win</span><span class="pun">-</span><span class="pln">requirements</span><span class="pun">.</span><span class="pln">txt </span><span class="pun">––</span><span class="pln">user</span></pre>

<p>
	على نظام ماك macOS:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_8" style=""><span class="pln">pip3 install </span><span class="pun">--</span><span class="pln">user </span><span class="pun">–</span><span class="pln">r automate</span><span class="pun">-</span><span class="pln">mac</span><span class="pun">-</span><span class="pln">requirements</span><span class="pun">.</span><span class="pln">txt </span><span class="pun">--</span><span class="pln">user</span></pre>

<p>
	على نظام لينكس:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_10" style=""><span class="pln">pip3 install </span><span class="pun">--</span><span class="pln">user </span><span class="pun">–</span><span class="pln">r automate</span><span class="pun">-</span><span class="pln">linux</span><span class="pun">-</span><span class="pln">requirements</span><span class="pun">.</span><span class="pln">txt </span><span class="pun">--</span><span class="pln">user</span></pre>

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

<ul>
	<li>
		<code>pip install --user send2trash==1.5.0</code>
	</li>
	<li>
		<code>pip install --user requests==2.21.0</code>
	</li>
	<li>
		<code>pip install --user beautifulsoup4==4.7.1</code>
	</li>
	<li>
		<code>pip install --user selenium==3.141.0</code>
	</li>
	<li>
		<code>pip install --user openpyxl==2.6.1</code>
	</li>
	<li>
		<code>pip install --user PyPDF2==1.26.0</code>
	</li>
	<li>
		<code>pip install --user python-docx==0.8.10</code> ‫(تثبيت‫ <code>python-docx</code> وليس <code>docx</code>)
	</li>
	<li>
		<code>pip install --user imapclient==2.1.0</code>
	</li>
	<li>
		<code>pip install --user pyzmail36==1.0.4</code>
	</li>
	<li>
		<code>pip install --user twilio</code>
	</li>
	<li>
		<code>pip install --user ezgmail</code>
	</li>
	<li>
		<code>pip install --user ezsheets</code>
	</li>
	<li>
		<code>pip install --user pillow==9.2.0</code>
	</li>
	<li>
		<code>pip install --user pyobjc-framework-Quartz==5.2</code> (على نظام ماك فقط)
	</li>
	<li>
		<code>pip install --user pyobjc-core==5.2</code> (على نظام ماك فقط)
	</li>
	<li>
		<code>pip install --user pyobjc==5.2</code> (على نظام ماك فقط)
	</li>
	<li>
		<code>pip install --user python3-xlib==0.15</code> (على نظام لينكس فقط)
	</li>
	<li>
		<code>pip install --user pyautogui</code>
	</li>
</ul>

<p>
	<strong>ملاحظة</strong>: يمكن أن يستغرق تثبيت الوحدة <code>pyobjc</code> في نظام ماك 20 دقيقة أو أكثر، لذا لا تنزعج إذا استغرق الأمر بعض الوقت، ويجب عليك أيضًا تثبيت الوحدة <code>pyobjc-core</code> أولًا، مما سيؤدي إلى تقليل وقت التثبيت الإجمالي.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4185_12" style=""><span class="pln"> pip install </span><span class="pun">--</span><span class="pln">user </span><span class="pun">-</span><span class="pln">U MODULE </span><span class="pun">أو</span><span class="pln"> pip3 install </span><span class="pun">--</span><span class="pln">user </span><span class="pun">-</span><span class="pln">U MODULE </span></pre>

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

<p>
	تُجرِي الإصدارات الأحدث من وحدات Selenium و OpenPyXL تغييرات غير متوافقة مع الإصدارات السابقة المُستخدَمة في هذه السلسلة من المقالات، بينما تتفاعل وحدات Twilio و EZGmail و EZSheets مع الخدمات عبر الإنترنت، ولكن قد يُطلَب منك تثبيت أحدث إصدار من هذه الوحدات باستخدام الأمر:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4185_6" style=""><span class="pln">pip install </span><span class="pun">--</span><span class="pln">user </span><span class="pun">-</span><span class="pln">U</span></pre>

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

<h2 id="-mu">
	تثبيت وحدات للمحرّر Mu
</h2>

<p>
	يمتلك محرّر Mu بيئة بايثون الخاصة به، وهي منفصلة عن البيئة التي تمتلكها عمليات تثبيت بايثون النموذجية، إذ يمكنك تثبيت الوحدات بحيث تستخدمها في السكربتات التي يشغّلها المحرّر Mu من خلال إظهار لوحة المدير Admin Panel عند النقر على رمز الترس في الزاوية اليمنى السفلية للمحرّر Mu، ثم انقر على تبويب الحزم الخارجية Third Party Packages في النافذة التي ستظهر واتبع الإرشادات الخاصة بتثبيت الوحدات في هذا التبويب. لا تزال القدرة على تثبيت الوحدات في المحرّر Mu ميزة حديثة وقيد التطوير، لذا قد تتغير هذه التعليمات.
</p>

<p>
	إن لم تتمكّن من تثبيت الوحدات باستخدام لوحة المدير، فيمكنك أيضًا فتح نافذة الطرفية وتشغيل الأداة pip الخاصة بالمحرّر Mu. يجب أن تستخدم خيار سطر الأوامر <code>‎--target</code> الخاص بالأداة pip لتحديد مجلد الوحدة الخاص بالمحرّر Mu، وهذا المجلد على نظام ويندوز هو:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4185_10" style=""><span class="pln"> C</span><span class="pun">:</span><span class="pln">\Users\&lt;USERNAME</span><span class="pun">&gt;</span><span class="pln">\AppData\Local\Mu\pkgs</span></pre>

<p>
	وعلى نظام ماك macOS:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4185_8" style=""><span class="pun">‎/</span><span class="typ">Applications</span><span class="pun">/</span><span class="pln">mu</span><span class="pun">-</span><span class="pln">editor</span><span class="pun">.</span><span class="pln">app</span><span class="pun">/</span><span class="typ">Contents</span><span class="pun">/</span><span class="typ">Resources</span><span class="pun">/</span><span class="pln">app_packages</span></pre>

<p>
	ولكنك لا تحتاج في نظام لينكس إلى إدخال الوسيط <code>‎--target</code> ، لذا شغّل الأمر <code>pip3</code> فقط.
</p>

<p>
	شغّل الأوامر التالية مثلًا بعد تنزيل ملف المتطلبات لنظام تشغيلك من <a href="https://nostarch.com/automatestuff2/" rel="external nofollow">موقع nostarch</a>:
</p>

<p>
	على نظام ويندوز:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_12" style=""><span class="pln">pip install </span><span class="pun">–</span><span class="pln">r automate</span><span class="pun">-</span><span class="pln">win</span><span class="pun">-</span><span class="pln">requirements</span><span class="pun">.</span><span class="pln">txt </span><span class="pun">--</span><span class="pln">target </span><span class="str">"C:\Users\USERNAME\AppData\Local\Mu\pkgs"</span></pre>

<p>
	على نظام ماك macOS:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_14" style=""><span class="pln">pip3 install </span><span class="pun">–</span><span class="pln">r automate</span><span class="pun">-</span><span class="pln">mac</span><span class="pun">-</span><span class="pln">requirements</span><span class="pun">.</span><span class="pln">txt </span><span class="pun">--</span><span class="pln">target </span><span class="pun">/</span><span class="typ">Applications</span><span class="pun">/</span><span class="pln">mu</span><span class="pun">-</span><span class="pln">editor</span><span class="pun">.</span><span class="pln">app</span><span class="pun">/</span><span class="typ">Contents</span><span class="pun">/</span><span class="typ">Resources</span><span class="pun">/</span><span class="pln">app_packages</span></pre>

<p>
	على نظام لينكس:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_16" style=""><span class="pln">pip3 install </span><span class="pun">--</span><span class="pln">user </span><span class="pun">–</span><span class="pln">r automate</span><span class="pun">-</span><span class="pln">linux</span><span class="pun">-</span><span class="pln">requirements</span><span class="pun">.</span><span class="pln">txt</span></pre>

<p>
	إذا أردتَ تثبيت بعض الوحدات فقط، فيمكنك تشغيل الأمر <code>pip</code> (أو <code>pip3</code>) العادي وإضافة الوسيط <code>‎--target</code>.
</p>

<h2 id="-">
	تشغيل البرامج في بايثون
</h2>

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

<h3 id="-terminal">
	تشغيل البرامج من نافذة الطرفية Terminal
</h3>

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

<p>
	يمكنك فتح نافذة طرفية على نظام ويندوز من خلال النقر على زر "ابدأ أو Start"، ثم أدخل إلى موجّه الأوامر، واضغط على مفتاح <code>ENTER</code>. انقر على أيقونة Spotlight في الجزء العلوي الأيمن في نظام ماك macOS، واكتب Terminal، ثم اضغط على مفتاح <code>ENTER</code>. يمكنك في نظام أوبنتو لينكس Ubuntu Linux الضغط على مفتاح <code>WIN</code> لإظهار أيقونة Dash، ثم اكتب Terminal، واضغط على مفتاح <code>ENTER</code>، وسيفتح اختصار لوحة المفاتيح <code>Ctrl-Alt-T</code> أيضًا نافذة الطرفية على نظام أوبنتو.
</p>

<p>
	تحتوي الصدفة التفاعلية على سطر الأوامر <code>&lt;&lt;&lt;</code>، وتعرض الطرفية أيضًا هذا السطر لإدخال الأوامر. سيكون المسار التالي هو المسار الكامل للمجلد الذي تتواجد فيه حاليًا على نظام ويندوز:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_18" style=""><span class="pln">C</span><span class="pun">:</span><span class="pln">\Users\Al</span><span class="pun">&gt;</span><span class="pln">your commands go here</span></pre>

<p>
	يعرض سطر الأوامر على نظام ماك macOS اسم حاسوبك ونقطتين ومجلد العمل الحالي (مع تمثيل مجلد المنزل home directory بالرمز <code>~</code> اختصارًا) واسم المستخدم الخاص بك متبوعًا بإشارة الدولار الأمريكي (<code>$</code>) كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_20" style=""><span class="typ">Als</span><span class="pun">-</span><span class="typ">MacBook</span><span class="pun">-</span><span class="typ">Pro</span><span class="pun">:~</span><span class="pln"> al$ your commands go here</span></pre>

<p>
	يشبه سطر الأوامر في نظام أوبنتو لينكس سطرَ الأوامر في نظام ماك macOS باستثناء أنه يبدأ باسم المستخدم والإشارة <code>@</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_22" style=""><span class="pln">al@al</span><span class="pun">-</span><span class="typ">VirtualBox</span><span class="pun">:~</span><span class="pln">$ your commands go here</span></pre>

<p>
	<strong>ملاحظة</strong>: يمكن تخصيص سطور الأوامر، ولكن لن نوضّح ذلك في هذا المقال.
</p>

<p>
	إذا أدخلتَ أمرًا مثل الأمر <code>python</code> على نظام ويندوز أو الأمر <code>python3</code> على نظامي ماك macOS ولينكس، فستتحقق الطرفية من وجود برنامج يحمل هذا الاسم في المجلد الذي تتواجد فيه حاليًا، وإذا لم تجده هناك، فستتحقق من المجلدات المُدرَجة في متغير البيئة <code>PATH</code>، حيث يمكن عَدّ متغيرات البيئة بأنها متغيرات على مستوى نظام التشغيل بأكمله، إذ تحتوي على عددٍ من إعدادات النظام. يمكنك رؤية القيمة المُخزَّنة في متغير البيئة <code>PATH</code> من خلال تشغيل الأمر <code>echo %PATH%‎</code> على نظام ويندوز والأمر <code>echo $PATH</code> على نظامي ماك macOS ولينكس. إليك مثال على نظام ماك macOS:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_24" style=""><span class="typ">Als</span><span class="pun">-</span><span class="typ">MacBook</span><span class="pun">-</span><span class="typ">Pro</span><span class="pun">:~</span><span class="pln"> al$ echo $PATH
</span><span class="pun">/</span><span class="typ">Library</span><span class="pun">/</span><span class="typ">Frameworks</span><span class="pun">/</span><span class="typ">Python</span><span class="pun">.</span><span class="pln">framework</span><span class="pun">/</span><span class="typ">Versions</span><span class="pun">/</span><span class="lit">3.9</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">:/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">local</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">:/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">
bin</span><span class="pun">:/</span><span class="pln">bin</span><span class="pun">:/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">sbin</span><span class="pun">:/</span><span class="pln">sbin</span></pre>

<p>
	يوجد ملف البرنامج python3 على نظام ماك macOS في المجلدك
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4185_14" style=""><span class="pln"> </span><span class="pun">‎/</span><span class="typ">Library</span><span class="pun">/</span><span class="typ">Frameworks</span><span class="pun">/</span><span class="typ">Python</span><span class="pun">.</span><span class="pln">framework</span><span class="pun">/</span><span class="typ">Versions</span><span class="pun">/</span><span class="lit">3.9</span><span class="pun">/</span><span class="pln">bin</span></pre>

<p>
	لذلك لا حاجة لإدخال المسار الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4185_16" style=""><span class="pun">‎/</span><span class="typ">Library</span><span class="pun">/</span><span class="typ">Frameworks</span><span class="pun">/</span><span class="typ">Python</span><span class="pun">.</span><span class="pln">framework</span><span class="pun">/</span><span class="typ">Versions</span><span class="pun">/</span><span class="lit">3.9</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">python3</span></pre>

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

<p>
	إذا أردتَ تشغيل برنامج <code>‎.py</code>، فيجب أن تدخِل الأمر <code>python</code> (أو <code>python3</code>) متبوعًا باسم ملف <code>‎.py</code>، مما يؤدي إلى تشغيل بايثون التي تشغّل بدورها الشيفرة البرمجية التي تجدها في ملف <code>‎.py</code>، وستعود إلى موجّه الطرفية بعد انتهاء برنامج بايثون. سيبدو برنامج بسيط يظهِر الرسالة "Hello, world!‎" مثلًا في نظام ويندوز كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_26" style=""><span class="typ">Microsoft</span><span class="pln"> </span><span class="typ">Windows</span><span class="pln"> </span><span class="pun">[</span><span class="typ">Version</span><span class="pln"> </span><span class="lit">10.0</span><span class="pun">.</span><span class="lit">17134.648</span><span class="pun">]</span><span class="pln">
</span><span class="pun">(</span><span class="pln">c</span><span class="pun">)</span><span class="pln"> </span><span class="lit">2018</span><span class="pln"> </span><span class="typ">Microsoft</span><span class="pln"> </span><span class="typ">Corporation</span><span class="pun">.</span><span class="pln"> </span><span class="typ">All</span><span class="pln"> rights reserved</span><span class="pun">.</span><span class="pln">

C</span><span class="pun">:</span><span class="pln">\Users\Al</span><span class="pun">&gt;</span><span class="pln">python hello</span><span class="pun">.</span><span class="pln">py
</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> world</span><span class="pun">!</span><span class="pln">

C</span><span class="pun">:</span><span class="pln">\Users\Al</span><span class="pun">&gt;</span></pre>

<p>
	يؤدي تشغيل الأمر <code>python</code> (أو <code>python3</code>) بدون أيّ اسم ملف إلى أن تشغّل بايثون الصدفة التفاعلية.
</p>

<h3 id="-">
	تشغيل برامج بايثون على نظام ويندوز
</h3>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4185_18" style=""><span class="pln"> py C</span><span class="pun">:</span><span class="pln">\path\to\your\pythonScript</span><span class="pun">.</span><span class="pln">py </span></pre>

<p>
	وكما هو موضح في الشكل التالي، يكون البرنامج py.exe مثبَّتًا على المسار <code>C:\Windows\py.exe</code> الموجود في متغير البيئة <code>PATH</code>، وتُعَد كتابة امتداد الملف <code>‎.exe</code> أمرًا اختياريًا عند تشغيل البرامج.
</p>

<p style="text-align: center;">
	<img alt="01_000028.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="165043" data-ratio="59.32" data-unique="yspvxim1b" width="381" src="https://academy.hsoub.com/uploads/monthly_2025_01/01_000028.jpg.22d654f209eb29e440f917b9c076d710.jpg">
</p>

<p style="text-align: center;">
	مربع حوار التشغيل Run في نظام ويندوز
</p>

<p>
	الجانب السلبي لهذه الطريقة هو أنه يجب أن تدخِل المسار الكامل للسكربت الخاص بك، وإذا شغّلنا سكربت بايثون من مربع الحوار، فستُفتح نافذة طرفية جديدة لعرض خرج هذا السكربت، وستُغلق هذه النافذة تلقائيًا عند انتهاء البرنامج، وبالتالي قد تفوِّت بعض الخرج. يمكنك حل هذه المشاكل من خلال إنشاء سكربت دفعي Batch Script، والذي هو ملف نصي صغير له امتداد الملف <code>‎.bat</code> ويمكنه تشغيل أوامر طرفية متعددة، وهو يشبه إلى حد كبير سكربت الصدفة Shell Script في نظامي ماك macOS ولينكس. يمكنك استخدام محرّر نصوص مثل المفكرة Notepad لإنشاء هذه الملفات.
</p>

<p>
	ننشئ ملف دفعي من خلال إنشاء ملف نصي جديد يحتوي على سطر واحد كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_28" style=""><span class="lit">@py</span><span class="pun">.</span><span class="pln">exe C</span><span class="pun">:</span><span class="pln">\path\to\your\pythonScript</span><span class="pun">.</span><span class="pln">py </span><span class="pun">%*</span><span class="pln">
</span><span class="lit">@pause</span></pre>

<p>
	ضع مسار برنامجك المطلق مكان المسار السابق، واحفظ هذا الملف مع امتداد الملف ‎<code>‎.bat</code>‎ مثل الملف pythonScript.bat. تمنع الإشارة <code>@</code> الموجودة في بداية كل أمر عرضَه في نافذة الطرفية، ويوجّه الرمز <code>*%</code> أيّ وسطاء مُدخَلة في سطر الأوامر بعد اسم الملف الدفعي إلى سكربت بايثون، ويقرأ برنامج بايثون بدوره وسطاء سطر الأوامر من قائمة <code>sys.argv</code>. سيمنعك هذا الملف الدفعي من الاضطرار إلى كتابة المسار المطلق الكامل لبرنامج بايثون في كل مرة تريد تشغيله فيها، وسيضيف <code>‎@pause</code> عبارة الضغط على أيّ مفتاح للمتابعة <code>‎"Press any key to continue..."‎</code> بعد نهاية سكربت بايثون لمنع اختفاء نافذة البرنامج بسرعة كبيرة. ننصحك بوضع جميع الملفات الدفعية وملفات <code>‎.py</code> في مجلد واحد موجود فعليًا في متغير البيئة <code>PATH</code> مثل المجلد <code>C:\Users\&lt;USERNAME&gt;‎</code>.
</p>

<p>
	لن تحتاج من خلال إعداد ملف دفعي لتشغيل سكربت بايثون إلى فتح نافذة طرفية وكتابة مسار الملف الكامل واسم سكربت بايثون الخاص بك، إذ يمكنك فقط الضغط على الاختصار <code>WIN-R</code> وإدخال <code>pythonScript</code> (اسم الملف <code>pythonScript.bat</code> الكامل ليس ضروريًا)، ثم اضغط على مفتاح <code>ENTER</code> لتشغيل السكربت الخاص بك.
</p>

<h3 id="-macos">
	تشغيل برامج بايثون على نظام ماك macOS
</h3>

<p>
	يمكنك إنشاء سكربت صدفة لتشغيل سكربتات بايثون الخاصة بك في نظام ماك macOS من خلال إنشاء ملف نصي له امتداد الملف <code>‎.command</code>. أنشئ ملفًا جديدًا في محرّر النصوص مثل المحرّر TextEdit وأضِف المحتوى التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_30" style=""><span class="com">#!/usr/bin/env bash</span><span class="pln">
 python3 </span><span class="pun">/</span><span class="pln">path</span><span class="pun">/</span><span class="pln">to</span><span class="pun">/</span><span class="pln">your</span><span class="pun">/</span><span class="pln">pythonScript</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	احفظ هذا الملف مع امتداد الملف <code>‎.command</code> في مجلدك الرئيسي (مثل المجلد <code>‎/Users/al</code>)، واجعل سكربت الصدفة قابلًا للتنفيذ من خلال تشغيل الأمر <code>chmod u+x yourScript.command</code> في نافذة الطرفية. ستتمكّن الآن من النقر على أيقونة Spotlight (أو الضغط على الاختصار ‎<img alt="02_000064.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="165044" data-ratio="100.00" data-unique="tucsgycn6" width="15" src="https://academy.hsoub.com/uploads/monthly_2025_01/02_000064.jpg.545ef8f7c2b9cbf7aa991d59ba088774.jpg">-SPACE) وإدخال <code>yourScript.command</code> لتشغيل سكربت الصدفة، والذي بدوره سيشغّل سكربت بايثون الخاص بك.
</p>

<h3 id="-">
	تشغيل برامج بايثون على نظام أوبنتو لينكس
</h3>

<p>
	يتطلب تشغيل سكربتات بايثون في أوبنتو لينكس من قائمة Dash إعدادًا إضافيًا. لنفترض أن لدينا السكربت <code>‎/home/al/example.py</code>، إذ قد يكون سكربت بايثون الخاص بك موجودًا في مجلد مختلف وباسم ملف مختلف، ونريد تشغيله من قائمة Dash. استخدم أولًا محرر نصوص مثل المحرّر <code>gedit</code> لإنشاء ملف جديد مع المحتوى التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_34" style=""><span class="pun">[</span><span class="typ">Desktop</span><span class="pln"> </span><span class="typ">Entry</span><span class="pun">]</span><span class="pln">
</span><span class="typ">Name</span><span class="pun">=</span><span class="pln">example</span><span class="pun">.</span><span class="pln">py
</span><span class="typ">Exec</span><span class="pun">=</span><span class="pln">gnome</span><span class="pun">-</span><span class="pln">terminal </span><span class="pun">--</span><span class="pln"> </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="pln">al</span><span class="pun">/</span><span class="pln">example</span><span class="pun">.</span><span class="pln">sh
</span><span class="typ">Type</span><span class="pun">=</span><span class="typ">Application</span><span class="pln">
</span><span class="typ">Categories</span><span class="pun">=</span><span class="pln">GTK</span><span class="pun">;</span><span class="pln">GNOME</span><span class="pun">;</span><span class="typ">Utility</span><span class="pun">;</span></pre>

<p>
	احفظ هذا الملف في المجلد الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4185_22" style=""><span class="pun">‎/</span><span class="pln">home</span><span class="pun">/&lt;</span><span class="pln">al</span><span class="pun">&gt;/.</span><span class="pln">local</span><span class="pun">/</span><span class="pln">share</span><span class="pun">/</span><span class="pln">applications </span></pre>

<p>
	(مع وضع اسم مستخدمك مكان <code>al</code>) بالاسم example.desktop. إن لم يُظهِر محرّر النصوص مجلد <code>‎.local</code> لأن المجلدات التي تبدأ بنقطة تُعَد مجلدات مخفية، فيجب أن تحفظه في مجلدك الرئيسي (مثل ‎<code>/home/al</code>‎) وتفتح نافذة طرفية لنقل الملف باستخدام الأمرك
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4185_20" style=""><span class="pln"> mv </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="pln">al</span><span class="pun">/</span><span class="pln">example</span><span class="pun">.</span><span class="pln">desktop </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="pln">al</span><span class="pun">/.</span><span class="pln">local</span><span class="pun">/</span><span class="pln">share</span><span class="pun">/</span><span class="pln">applications</span><span class="pun">.</span></pre>

<p>
	إذا كان الملف example.desktop موجودًا في المجلد الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4185_24" style=""><span class="pln"> </span><span class="pun">‎/</span><span class="pln">home</span><span class="pun">/</span><span class="pln">al</span><span class="pun">/.</span><span class="pln">local</span><span class="pun">/</span><span class="pln">share</span><span class="pun">/</span><span class="pln">applications</span></pre>

<p>
	فستتمكن من الضغط على مفتاح <code>Windows</code> في لوحة المفاتيح لإظهار قائمة Dash وكتابة example.py (أو أي شيء تضعه في الحقل <code>Name</code>)، مما يؤدي إلى فتح نافذة طرفية جديدة أو برنامج <code>gnome-terminal</code> على وجه التحديد الذي يشغّل سكربت الصدفة <code>‎/home/al/example.sh</code> الذي سننشئه لاحقًا.
</p>

<p>
	أنشئ ملفًا جديدًا مع المحتوى التالي في محرّر النصوص:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_36" style=""><span class="com">#!/usr/bin/env bash</span><span class="pln">
python3 </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="pln">al</span><span class="pun">/</span><span class="pln">example</span><span class="pun">.</span><span class="pln">py
bash</span></pre>

<p>
	احفظ هذا الملف في الملف <code>‎/home/al/example.sh</code> الذي هو سكربت صدفة، والذي هو سكربت يشغّل سلسلةً من أوامر الطرفية، حيث يشغّل سكربت الصدفة سكربت بايثون <code>‎/home/al/example.py</code> ثم يشغّل برنامج صدفة باش Bash Shell. إن لم نضع أمر باش الموجود في السطر الأخير، فستُغلَق نافذة الطرفية بعد انتهاء سكربت بايثون وستفقد أيّ نصٍ يعرضه استدعاء الدالة <code>print()‎</code> على الشاشة.
</p>

<p>
	يجب أن تضيف أذونات التنفيذ إلى سكربت الصدفة، لذا شغّل الأمر التالي من نافذة الطرفية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8838_38" style=""><span class="pln">al@ubuntu</span><span class="pun">:~</span><span class="pln">$ chmod u</span><span class="pun">+</span><span class="pln">x </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="pln">al</span><span class="pun">/</span><span class="pln">example</span><span class="pun">.</span><span class="pln">sh</span></pre>

<p>
	أعددنا الملفين example.desktop و example.sh، وستتمكّن الآن من تشغيل السكربت example.py من خلال الضغط على مفتاح <code>Windows</code> وإدخال example.py أو أي اسم تضعه في الحقل <code>Name</code> الخاص بالملف example.desktop.
</p>

<h3 id="-assertions">
	تشغيل برامج بايثون مع تعطيل التأكيدات Assertions
</h3>

<p>
	يمكنك تعطيل تعليمات <code>assert</code> في برامج بايثون الخاصة بك للحصول على تحسين بسيط في الأداء، لذا ضمّن مفتاح <code>‎-O</code> بعد الأمر <code>python</code> أو <code>python3</code> وقبل اسم ملف ‎<code>.py</code>‎ عند تشغيل بايثون من الطرفية، مما يؤدي إلى تشغيل نسخة مُحسَّنة من برنامجك تتخطى عمليات التحقق من التأكيد.
</p>

<h2 id="-3">
	أين تجد المساعدة
</h2>

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

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

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

<p>
	لنسبب خطأً عمدًا في برنامجنا للتجربة: أدخل ‎'42' + 3 في الصدفة التفاعلية، لا حاجة إلى شرح ما الذي تفعله هذه الشيفرة الآن لأننا سنتعلمها لاحقًا، لكن سيظهر لك الخطأ الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8307_27" style=""><span class="pln">   </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'42'</span><span class="pln"> </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="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
     </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;pyshell#0&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
       </span><span class="str">'42'</span><span class="pln"> </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="typ">TypeError</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Can</span><span class="str">'t convert '</span><span class="pln">int</span><span class="str">' object to str implicitly
   &gt;&gt;&gt;</span></pre>

<p>
	رسالة الخطأ ➋ تظهر لأن بايثون لا تستطيع فهم التعليمة التي أعطيتها إياها، والجزء الأول ➊ من رسالة الخطأ يبين لنا التعليمة الخطأ ورقم سطرها وما المشكلة التي واجهتها بايثون معها. إذا لم تكن متأكدًا من معنى رسالة الخطأ فابحث عنها في الويب. أدخل "TypeError: Can’t convert ‘int’ object to str implicitly" (بما فيها علامات الاقتباس) في محرك البحث المفضل لديك وستجد عشرات الصفحات التي توضح لك ما هذا الخطأ وما مسبباته كما في الصورة الآتية:
</p>

<p style="text-align: center;">
	<img alt="نتائج بحث جوجل حول رسالة خطأ برمجي.png" class="ipsImage ipsImage_thumbnailed" data-fileid="149375" data-ratio="67.86" data-unique="5ux4twvwj" style="width: 650px; height: auto;" width="868" src="https://academy.hsoub.com/uploads/monthly_2024_05/1641947175_.png.f9c18d1c02861f90cae5fb97b617fb1e.png">
</p>

<p style="text-align: center;">
	الشكل 2: نتائج بحث جوجل حول رسالة خطأ برمجي
</p>

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

<h2 id="-4">
	طرح أسئلة برمجية ذكية
</h2>

<p>
	إذا لم تجد إجابةً عن سؤالك في الإنترنت، فيمكنك أن تجرب سؤال الخبراء في أحد المنتديات أو المواقع المخصصة مثل Stack Overflow أو مجتمع Learn Programming في Reddit. لكن أبقِ في ذهنك أن هنالك طرائق ذكية لطرح الأسئلة البرمجة لتساعد الآخرين على مساعدتك. فبدايةً احرص على قراءة قسم الأسئلة الشائعة FAQ في تلك المواقع لتعرف الطريقة الصحيحة لطرح السؤال.
</p>

<p>
	حين طرحك لسؤال برمجي فتذكر ما يلي:
</p>

<ul>
	<li>
		اشرح ما تحاول فعله، وليس ما فعلته. هذا يسمح لمن يريد مساعدته أن يخبرك إن كنت على الطريق الصحيح لحل المشكلة.
	</li>
	<li>
		حدد النقطة التي يحدث الخطأ عندها، هل تحدث مثلًا حين بدء تشغيل البرنامج كل مرة أم حين وقوع حدث معين؟ وما هو هذا الحدث الذي يحدث ويسبب ظهور الخطأ.
	</li>
	<li>
		انسخ والصق رسالة الخطأ كاملة على مواقع تسمح لك بمشاركة الشيفرات مع الآخرين بسرعة مثل <a href="http://pastebin.com" rel="external nofollow">pastebin</a> أو <a href="http://gits.github.com" rel="external nofollow">gits.github</a> أو <a href="https://academy.hsoub.com/questions/c3-programming/" rel="">قسم الأسئلة والأجوبة في أكاديمية حسوب</a>، فعبرها تستطيع مشاركة نصوص طويلة دون أن تفقد تنسيق النص، وبعد ذلك ضع <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/" rel="">رابط URL</a> التابع للشيفرة التي شاركتها في مشاركتك أو سؤالك.
	</li>
	<li>
		اشرح ما حاولت فعله لحل المشكلة، وبهذا تخبر الآخرين أنك بذلت جهدًا لمحاولة حل المشكلة بنفسك.
	</li>
	<li>
		ضع إصدار بايثون الذي تستخدمه (إذ هنالك اختلافات جوهرية بين الإصدار الثاني من مفسر بايثون والإصدار الثالث). اذكر أيضًا نوع <a href="https://academy.hsoub.com/programming/os-embedded-systems/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A3%D9%86%D8%B8%D9%85%D8%A9-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84/" rel="">نظام تشغيلك</a> وإصداره.
	</li>
	<li>
		إذا حدث الخطأ بعد إجراء تعديل على شيفرتك فاذكر ما هو التعديل الذي أجريته.
	</li>
</ul>

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

<h2 id="-5">
	الخلاصة
</h2>

<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>

<p>
	ترجمة -وبتصرف- لمقدمة كتاب <a href="https://automatetheboringstuff.com/2e/chapter0/" rel="external nofollow">Automate the boring stuff with Python</a> لصاحبه Al Sweigart.
</p>

<h2 id="-6">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/python/" rel="">تعلم لغة بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D9%85%D9%85%D9%8A%D8%B2%D8%A7%D8%AA-%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://academy.hsoub.com/programming/python/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%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://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>
</ul>
]]></description><guid isPermaLink="false">2322</guid><pubDate>Sun, 05 May 2024 16:00:00 +0000</pubDate></item><item><title>&#x628;&#x646;&#x627;&#x621; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646; &#x64A;&#x62C;&#x64A;&#x628; &#x639;&#x644;&#x649; &#x623;&#x633;&#x626;&#x644;&#x629; &#x645;&#x644;&#x641; PDF &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x627;&#x644;&#x630;&#x643;&#x627;&#x621; &#x627;&#x644;&#x627;&#x635;&#x637;&#x646;&#x627;&#x639;&#x64A;</title><link>https://academy.hsoub.com/programming/python/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D9%8A%D8%AC%D9%8A%D8%A8-%D8%B9%D9%84%D9%89-%D8%A3%D8%B3%D8%A6%D9%84%D8%A9-%D9%85%D9%84%D9%81-pdf-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%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-r2265/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_03/--------PDF----(1).png.c1af3fe12a171a203e8715d9e0d954c6.png" /></p>
<p>
	لقد أحدثت النماذج اللغوية الكبيرة LLMs وأشهرها روبوت المحادثة ChatGPT الذي طورته شركة OpenAI ثورة في الكثير من المجالات وأثبتت قدرتها على توليد نصوص تشبه النصوص البشرية، كما سهلت أداء العديد من المهام في مختلف المجالات ومن أبرزها مجال تطوير البرمجيات، فقد وفرت للمطورين والمبرمجين واجهات برمجية APIs تساعدهم في إنشاء تطبيقات ذكاء اصطناعي بسهولة كبيرة. سنتعلم في مقال اليوم كيفية تطوير تطبيق بايثون قادر على فهم نصوص ملف PDF والإجابة على أي أسئلة نطرحها حول محتوى هذا الملف بالاستفادة من ميزات نماذج الذكاء الاصطناعي التي توفرها واجهة برمجة تطبيقات OpenAI <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> وإطار عمل LangChain، وهو إطار عمل للغة البرمجة بايثون يمكن دمجه في تطبيقاتك لتعزز إمكانيات النماذج اللغوية الكبيرة.
</p>

<h2 id="">
	نظرة عامة على التطبيق المطلوب ومتطلباته
</h2>

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

<ul>
	<li>
		معرفة بأساسيات لغة بايثون <a href="https://academy.hsoub.com/programming/python/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%AA%D9%87%D8%A7-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r714/" rel="">وتثبيت بيئة بايثون</a> على الحاسوب المحلي.
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%84%D9%84%D9%85%D8%B4%D8%A7%D8%B1%D9%8A%D8%B9-%D9%85%D8%B9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1751/" rel="">تثبيت أداة pip</a> لتثبيت وإدارة حزم البرمجيات المساندة لبايثون.
	</li>
	<li>
		إنشاء حساب على على منصة OpenAI والحصول على مفتاح الواجهة البرمجية OpenAI <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> key خاص بك.
	</li>
	<li>
		معرفة بأساسيات نماذج وأطر عمل الذكاء الاصطناعي واختيار النماذج المناسبة لعمل التطبيق.
	</li>
	<li>
		معرفة بطريقة معالجة النصوص باستخدام التضمينات الرقمية ومخازن المتجهات.
	</li>
</ul>

<h2 id="-1">
	ما أهمية التضمينات الرقمية في تطبيقات البحث
</h2>

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

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="145758" href="https://academy.hsoub.com/uploads/monthly_2024_03/440915970_.png.09051577cd6b891e953063b6bcb50e9f.png" rel=""><img alt="متجهات وتضمينات" class="ipsImage ipsImage_thumbnailed" data-fileid="145758" data-unique="y8yruihdu" src="https://academy.hsoub.com/uploads/monthly_2024_03/.thumb.png.8310f322927d3179e51becb1d41ad976.png"> </a>
</p>

<h2 id="-2">
	خطوات التطبيق العملي
</h2>

<p>
	لننشئ <a href="https://academy.hsoub.com/programming/python/%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-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-tkinter-r1501/" rel="">تطبيق واجهة رسومية GUI بلغة بايثون</a> باستخدام المكتبة المدمجة Tkinter يمكننا من خلالها تحميل ملف PDF الذي نريده ثم نبدأ بمعالجة محتواه واستخراج كافة النصوص منه، فبعد تحميل الملف المطلوب سنحول نصوصه إلى تضمينات كما شرحنا سابقًا، ثم سنبدأ  بعملية طرح سؤال متعلق بمحتوى الملف. سنحول السؤال كذلك لتضمين أو تمثيل رقمي ونبحث عن كافة المحتوى المشابه له وسنرسل بعد ذلك للواجهة البرمجية ChatGPT <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> سلسلة تتضمن السؤال وكل المحتوى المرتبط به الذي وجدناه ضمن الملف كمدخلات، ثم سنولّد بناءً على ذلك الإجابة المناسبة بالاستفادة من إمكانيات النماذج اللغوية الكبيرة LLMs. وإليك خطوات القيام بذلك بالتفصيل:
</p>

<h3 id="1apiopenai">
	خطوة 1: الحصول على مفتاح <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> الخاص بك من OpenAI
</h3>

<p>
	للحصول على مفتاح <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> الخاص بك من OpenAI عليك اتباع الخطوات التالية:
</p>

<ul>
	<li>
		انتقل إلى <a href="https://openai.com/" rel="external nofollow">الصفحة الرسمية لمنصة openai</a> وأنشئ حسابًا جديدًا إذا لم تكن قد أنشأته من قبل ثم سجل الدخول لحسابك.
	</li>
	<li>
		انقر على القسم اAP للدخول لحسابك في صفحة مطوري OpenAI.
	</li>
	<li>
		انقر على أيقونة ChatGPT أعلى يمين الصفحة واختر البند <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> Keys.
	</li>
	<li>
		انقر على Create new secret key لإنشاء مفتاح <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>
</ul>

<p>
	هذا كل ما يلزم لإنشاء مفتاح <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> الخاص بك من OpenAI. سيبدأ المفتاح بـ sk-‎ انسخه واحفظه في مكان آمن واحرص على عدم مشاركته مع أحد أو كتابته في كود عام، فقد يقوم الآخرون باستخدام مفتاح <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> الخاص بك ويستهلكون رصيدك المتاح.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="145759" href="https://academy.hsoub.com/uploads/monthly_2024_03/API.png.b9abd9456bc5dd6e4b90c8018452c431.png" rel=""><img alt="مفتاح api" class="ipsImage ipsImage_thumbnailed" data-fileid="145759" data-unique="8csckwfms" src="https://academy.hsoub.com/uploads/monthly_2024_03/API.thumb.png.270ebe6e641fe8cec6ad92ef4b4e6454.png"> </a>
</p>

<p>
	ملاحظة: عليك الاشتراك بخطة مدفوعة للاستفادة من واجهة برمجة التطبيقات OpenAI <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> في تطبيقاتك، وسيكون المبلغ المقتطع بحسب الاستهلاك والنموذج المستخدم، فلكل نموذج تكلفة مختلفة وكلما زادت طلباتك أو عدد الرموز tokens المرسلة والمستقبلة من النموذج كلما زادت فاتورتك، لكن يمكنك في البداية الحصول على رصيد مجاني بقيمة ‎5 دولار‎‎‎ عند الاشتراك حديثًا في المنصة للتجربة.
</p>

<h3 id="2pdf">
	خطوة 2: إنشاء ملفات تطبيق بايثون اسأل PDF
</h3>

<p>
	للقيام بهذه الخطوة يجب أن تكون <a href="https://academy.hsoub.com/programming/python/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%AA%D9%87%D8%A7-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r714/" rel="">بيئة بايثون مثبتة على جهازك</a>، ولإنشاء مشروع بايثون جديد، افتح <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%A7-%D9%87%D9%88-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%9F-r353/" rel="">سطر الأوامر</a> (أو الطرفية) في نظام التشغيل وانتقل للمسار المطلوب، وأنشئ مجلدًا جديدًا للمشروع وليكن باسم <strong>askpdf</strong>، ثم أنشئ ضمنه ملفين الأول <strong>ask_pdf.py</strong> لإضافة كود الواجهة الرسومية للتطبيق، والثاني ملف ‎<strong>.env</strong> لإضافة مفتاح الواجهة الرسومية OpenAI <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> Key اللازمة لعمل التطبيق من خلال كتابة التعليمات التالية تباعًا في سطر الأوامر:
</p>

<pre class="ipsCode">C:\Users\PC&gt;d:
D:\&gt;md askpdf
D:\&gt;cd askpdf
D:\askpdf&gt;touch ask_pdf.py
Touching ask_pdf.py
D:\askpdf&gt;touch .env
Touching .env
D:\askpdf&gt;
</pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="PNG" data-fileid="145751" href="https://academy.hsoub.com/uploads/monthly_2024_03/633678544_.PNG.ce5be1bcc69a7a483130a30f01d4ea24.PNG" rel=""><img alt="إنشاء مجلد المشروع" class="ipsImage ipsImage_thumbnailed" data-fileid="145751" data-unique="e2pofm5oy" src="https://academy.hsoub.com/uploads/monthly_2024_03/633678544_.PNG.ce5be1bcc69a7a483130a30f01d4ea24.PNG"> </a>
</p>

<h3 id="-3">
	تثبيت المكتبات اللازمة لعمل التطبيق
</h3>

<p>
	يحتاج التطبيق إلى تثبيت العديد من مكتبات ووحدات بايثون الخارجية باستخدام مدير الحزم <code>pip</code> وهي كالتالي:
</p>

<pre class="ipsCode" id="ips_uid_137_9">pip install python-dotenv PyPDF2 langchain langchain-openai langchain-community faiss-cpu
</pre>

<p>
	إليك وصفًا موجزًا لكل مكتبة ولماذا استخدمناها في التطبيق:
</p>

<ul>
	<li>
		المكتبة python-dotenv لقراءة قيمة المفتاح الذي سأخزنه في الملف<code> env</code>.
	</li>
	<li>
		المكتبة PyPDF2 ضرورية للتعامل مع ملف PDF وقراءته محتوياته.
	</li>
	<li>
		إطار عمل LangChain ليسهل التعامل مع نموذج text-embedding-ada-002 لتقسيم النصوص، وإنشاء تضمينات وفهارس لها، كما أنه يدعم نموذج GPT-3.5 Turbo Instruct لتوليد إجابات على الأسئلة المطروحة.
	</li>
	<li>
		سنستدعي مكتبات langchain و langchain-openai و langchain-community من هذا الإطار وهي مكتبات مفيدة تتكامل مع نماذج OpenAI وتوسع إمكانياتها.
	</li>
	<li>
		وأخيرًا سنستخدم مكتبة Faiss وهي مكتبة بايثون يوفرها إطار LangChain تسرع عملية البحث عن التشابه في البيانات النصية دون الحاجة لاستهلاك الكثير من الموارد.
	</li>
</ul>

<h3 id="-4">
	كتابة الكود البرمجي للتطبيق
</h3>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4718_10" style=""><span class="pln">OPENAI_API_KEY</span><span class="pun">=</span><span class="pln"> </span><span class="typ">Your_KEY</span></pre>

<p>
	وعليك بالطبع استبدال Your_KEY في الكود السابق بالقيمة الفعلية لمفتاحك ليعمل التطبيق بشكل صحيح.
</p>

<p style="text-align: center;">
	<img alt="مفتاح الواجهة البرمجة" class="ipsImage ipsImage_thumbnailed" data-fileid="145775" data-ratio="15.50" data-unique="ouf1ot9h1" style="width: 600px; height: auto;" width="797" src="https://academy.hsoub.com/uploads/monthly_2024_03/1122237894_.PNG.1542806c372da3342f7971227fcea242.PNG">
</p>

<p>
	الآن سننتقل للملف الأساسي للتطبيق ask_pdf.py ونستورد بدايةً كافة المكتبات والوظائف اللازمة لعمل التطبيق. ويوضح التعليق ضمن الكود دور كل منها على النحو الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7759_7" style=""><span class="kwd">import</span><span class="pln"> os
</span><span class="kwd">from</span><span class="pln"> dotenv </span><span class="kwd">import</span><span class="pln"> load_dotenv
</span><span class="com"># مكتبات إنشاء الواجهة الرسومية</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><span class="kwd">from</span><span class="pln"> tkinter </span><span class="kwd">import</span><span class="pln"> filedialog</span><span class="pun">,</span><span class="pln"> scrolledtext</span><span class="pun">,</span><span class="pln"> ttk
</span><span class="kwd">from</span><span class="pln"> tkinter </span><span class="kwd">import</span><span class="pln"> font
</span><span class="kwd">from</span><span class="pln"> PIL </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Image</span><span class="pun">,</span><span class="pln"> </span><span class="typ">ImageTk</span><span class="pln">
</span><span class="com"># قراءة ومعالجة ملفات PDF</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> </span><span class="typ">PyPDF2</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">PdfReader</span><span class="pln">
</span><span class="com"># الواجهة البرمجية OpenAI</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> langchain_openai </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">OpenAI</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> langchain_community</span><span class="pun">.</span><span class="pln">vectorstores </span><span class="kwd">import</span><span class="pln"> FAISS
</span><span class="kwd">from</span><span class="pln"> langchain_community</span><span class="pun">.</span><span class="pln">callbacks </span><span class="kwd">import</span><span class="pln"> get_openai_callback
</span><span class="kwd">from</span><span class="pln"> langchain</span><span class="pun">.</span><span class="pln">text_splitter </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">CharacterTextSplitter</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> langchain</span><span class="pun">.</span><span class="pln">chains</span><span class="pun">.</span><span class="pln">question_answering </span><span class="kwd">import</span><span class="pln"> load_qa_chain
</span><span class="kwd">from</span><span class="pln"> langchain_openai </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">OpenAIEmbeddings</span></pre>

<p>
	بعدها سننشئ الصنف الأساسي للتطبيق باسم <code>askpdfgui</code> ونعرّف بداخله التابع <code>__init__</code> لإضافة وتهيئة <a href="https://academy.hsoub.com/programming/python/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%B9%D9%86%D8%A7%D8%B5%D8%B1-%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-widgets-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1502/" rel="">عناصر الواجهة الرسومية Widgets</a> للتطبيق، ستتضمن الواجهة عناصر متعددة مثل حاويات العناوين Labels وشريط تقدم Progressbar وزِرَّين Buttons الأول لتحميل ملف PDF من الجهاز لذاكرة التطبيق ومعالجته، والثاني للبحث عن إجابة السؤال الذي يكتبه المستخدم ولا يكون هذا الزر مُفعّلًًا إلا بعد اكتمال تحميل ومعالجة الملف.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7759_11" style=""><span class="kwd">class</span><span class="pln"> askpdfgui</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"> root</span><span class="pun">):</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">root </span><span class="pun">=</span><span class="pln"> root
        self</span><span class="pun">.</span><span class="pln">root</span><span class="pun">.</span><span class="pln">title</span><span class="pun">(</span><span class="str">"اسأل PDF"</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">root</span><span class="pun">.</span><span class="pln">geometry</span><span class="pun">(</span><span class="str">"800x700"</span><span class="pun">)</span><span class="pln">

        custom_font </span><span class="pun">=</span><span class="pln"> font</span><span class="pun">.</span><span class="typ">Font</span><span class="pun">(</span><span class="pln">family</span><span class="pun">=</span><span class="str">"Verdana"</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="lit">24</span><span class="pun">,</span><span class="pln"> weight</span><span class="pun">=</span><span class="str">"bold"</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">label </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">root</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"? PDF اسأل"</span><span class="pun">,</span><span class="pln"> font</span><span class="pun">=</span><span class="pln">custom_font</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">label</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">pady</span><span class="pun">=</span><span class="lit">10</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">progress_label </span><span class="pun">=</span><span class="pln"> ttk</span><span class="pun">.</span><span class="typ">Label</span><span class="pun">(</span><span class="pln">root</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">""</span><span class="pun">,</span><span class="pln"> foreground</span><span class="pun">=</span><span class="str">"green"</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">progress_label</span><span class="pun">.</span><span class="pln">pack</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">progress_bar </span><span class="pun">=</span><span class="pln"> ttk</span><span class="pun">.</span><span class="typ">Progressbar</span><span class="pun">(</span><span class="pln">root</span><span class="pun">,</span><span class="pln"> orient</span><span class="pun">=</span><span class="str">"horizontal"</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">progress_bar</span><span class="pun">.</span><span class="pln">pack</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">


        script_dir </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">dirname</span><span class="pun">(</span><span class="pln">os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">abspath</span><span class="pun">(</span><span class="pln">__file__</span><span class="pun">))</span><span class="pln">
        image_path </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">script_dir</span><span class="pun">,</span><span class="pln"> </span><span class="str">"robopdf.png"</span><span class="pun">)</span><span class="pln">
        image </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Image</span><span class="pun">.</span><span class="pln">open</span><span class="pun">(</span><span class="pln">image_path</span><span class="pun">)</span><span class="pln">
        tk_image </span><span class="pun">=</span><span class="pln"> </span><span class="typ">ImageTk</span><span class="pun">.</span><span class="typ">PhotoImage</span><span class="pun">(</span><span class="pln">image</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">image_label </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">root</span><span class="pun">,</span><span class="pln"> image</span><span class="pun">=</span><span class="pln">tk_image</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">image_label</span><span class="pun">.</span><span class="pln">image </span><span class="pun">=</span><span class="pln"> tk_image
        self</span><span class="pun">.</span><span class="pln">image_label</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">pady</span><span class="pun">=</span><span class="lit">10</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">upload_button </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">
            root</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"حمل ملفك هنا"</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">upload_pdf
        </span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">upload_button</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">pady</span><span class="pun">=</span><span class="lit">10</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">question_entry </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">root</span><span class="pun">,</span><span class="pln"> width</span><span class="pun">=</span><span class="lit">60</span><span class="pun">,</span><span class="pln"> justify</span><span class="pun">=</span><span class="str">"center"</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">question_entry</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">pady</span><span class="pun">=</span><span class="lit">10</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">ask_button </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">
            root</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"اطرح السؤال"</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">ask_question</span><span class="pun">,</span><span class="pln"> state</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">DISABLED
        </span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">ask_button</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">pady</span><span class="pun">=</span><span class="lit">10</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">result_text </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Text</span><span class="pun">(</span><span class="pln">root</span><span class="pun">,</span><span class="pln"> wrap</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">WORD</span><span class="pun">,</span><span class="pln"> width</span><span class="pun">=</span><span class="lit">60</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">=</span><span class="lit">10</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">result_text</span><span class="pun">.</span><span class="pln">configure</span><span class="pun">(</span><span class="pln">font</span><span class="pun">=(</span><span class="str">"TkDefaultFont"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">12</span><span class="pun">))</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">result_text</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">pady</span><span class="pun">=</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> anchor</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">CENTER</span><span class="pun">)</span><span class="pln"> </span></pre>

<p>
	سيكون شكل التطبيق على النحو التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="PNG" data-fileid="145750" href="https://academy.hsoub.com/uploads/monthly_2024_03/pdf.PNG.a3155a2883146311d18ec57c4c404266.PNG" rel=""><img alt="الواجهة الأولية لتطبيق اسأل pdf" class="ipsImage ipsImage_thumbnailed" data-fileid="145750" data-ratio="91.00" data-unique="du5fljb1k" style="width: 500px; height: auto;" width="600" src="https://academy.hsoub.com/uploads/monthly_2024_03/pdf.thumb.PNG.c478ee00cae3f76bb91c48411d9d3782.PNG"> </a>
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4718_22" style=""><span class="kwd">def</span><span class="pln"> upload_pdf</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
        file_path </span><span class="pun">=</span><span class="pln"> filedialog</span><span class="pun">.</span><span class="pln">askopenfilename</span><span class="pun">(</span><span class="pln">filetypes</span><span class="pun">=[(</span><span class="str">"PDF Files"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"*.pdf"</span><span class="pun">)])</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> file_path</span><span class="pun">:</span><span class="pln">
            self</span><span class="pun">.</span><span class="pln">process_pdf</span><span class="pun">(</span><span class="pln">file_path</span><span class="pun">)</span></pre>

<p>
	بعد أن يختار المستخدم ملف PDF يستدعى التابع <code>process_pdf</code> الذي يأخذ كوسيط مسار هذا الملف لبدء عملية المعالجة ويستخرج النصوص منه باستخدام الدالة <code>extract_text</code>، ويقسمه إلى أجزاء أو مقاطع أو نصوص بطول 1000 حرف مع تداخل بقيمة 200 حرف بين الأجزاء كي لا يفقد السياق، بمعنى سيكون الجزء الأول من البداية إلى الحرف 1000 أما الجزء الثاني فسيبدأ من الحرف 801 لضمان استمرارية المعنى وعدم فقدان معلومات مهمة بين النصوص المتجاورة.
</p>

<p>
	هناك عدة تقنيات مختلفة متاحة لتنفيذ مهمة التضمين والفهرسة في تطبيقنا، وقد اعتمدنا في هذا هذا التطبيق على الصنف OpenAIEmbeddings من مكتبة langchain_openai ومررنا قيمة مفتاح الواجهة البرمجية <code>openai_api_key</code> لباني الصنف لأنه سيستخدم هنا النموذج <a href="https://platform.openai.com/docs/guides/embeddings" rel="external nofollow">Embading</a> الذي توفره هذه الواجهة لتكوين التضمينات الرقمية وإنشاء المتجهات الخاصة بها بالاستعانة بمكتبة FAISS على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4718_24" style=""><span class="kwd">def</span><span class="pln"> process_pdf</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> file_path</span><span class="pun">):</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">progress_label</span><span class="pun">.</span><span class="pln">config</span><span class="pun">(</span><span class="pln">text</span><span class="pun">=</span><span class="str">"انتظر اكتمال تحميل ملف PDF..."</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">progress_bar</span><span class="pun">.</span><span class="pln">start</span><span class="pun">()</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">root</span><span class="pun">.</span><span class="pln">update_idletasks</span><span class="pun">()</span><span class="pln">
        pdf_reader </span><span class="pun">=</span><span class="pln"> </span><span class="typ">PdfReader</span><span class="pun">(</span><span class="pln">file_path</span><span class="pun">)</span><span class="pln">
        text </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"> page </span><span class="kwd">in</span><span class="pln"> pdf_reader</span><span class="pun">.</span><span class="pln">pages</span><span class="pun">:</span><span class="pln">
            text </span><span class="pun">+=</span><span class="pln"> page</span><span class="pun">.</span><span class="pln">extract_text</span><span class="pun">()</span><span class="pln">

        </span><span class="com"># تقسيم نص الملف إلى أجزاء</span><span class="pln">
        text_splitter </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CharacterTextSplitter</span><span class="pun">(</span><span class="pln">
            separator</span><span class="pun">=</span><span class="str">"\n"</span><span class="pun">,</span><span class="pln"> chunk_size</span><span class="pun">=</span><span class="lit">1000</span><span class="pun">,</span><span class="pln"> chunk_overlap</span><span class="pun">=</span><span class="lit">200</span><span class="pun">,</span><span class="pln"> length_function</span><span class="pun">=</span><span class="pln">len
        </span><span class="pun">)</span><span class="pln">
        chunks </span><span class="pun">=</span><span class="pln"> text_splitter</span><span class="pun">.</span><span class="pln">split_text</span><span class="pun">(</span><span class="pln">text</span><span class="pun">)</span><span class="pln">
        </span><span class="com"># إنشاء تضمينات النصوص</span><span class="pln">
        embeddings </span><span class="pun">=</span><span class="pln"> </span><span class="typ">OpenAIEmbeddings</span><span class="pun">(</span><span class="pln">api_key</span><span class="pun">=</span><span class="pln">openai_api_key</span><span class="pun">)</span><span class="pln">
        knowledge_base </span><span class="pun">=</span><span class="pln"> FAISS</span><span class="pun">.</span><span class="pln">from_texts</span><span class="pun">(</span><span class="pln">chunks</span><span class="pun">,</span><span class="pln"> embeddings</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">docs </span><span class="pun">=</span><span class="pln"> knowledge_base</span><span class="pun">.</span><span class="pln">similarity_search</span><span class="pun">(</span><span class="str">""</span><span class="pun">)</span></pre>

<p>
	بالنسبة للسطر الأخير في الكود:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4718_26" style=""><span class="pln">self</span><span class="pun">.</span><span class="pln">docs </span><span class="pun">=</span><span class="pln"> knowledge_base</span><span class="pun">.</span><span class="pln">similarity_search</span><span class="pun">(</span><span class="str">""</span><span class="pun">)</span></pre>

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

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4718_28" style=""><span class="pln">self</span><span class="pun">.</span><span class="pln">docs </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">{</span><span class="str">"text"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"تعلم لغات البرمجة يساعد في تطوير مهارات البرمجة"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"similarity_score"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.85</span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="str">"text"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"تعلم الذكاء الاصطناعي يحسن من تجربة المستخدم"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"similarity_score"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.92</span><span class="pun">},</span><span class="pln">
    </span><span class="com"># ... وهكذا</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4718_30" style=""><span class="pln"> self</span><span class="pun">.</span><span class="pln">progress_label</span><span class="pun">.</span><span class="pln">config</span><span class="pun">(</span><span class="pln">text</span><span class="pun">=</span><span class="str">"اكتملت عملية التحميل يمكنك طرح السؤال الآن"</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">progress_bar</span><span class="pun">.</span><span class="pln">stop</span><span class="pun">()</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">progress_bar</span><span class="pun">[</span><span class="str">"value"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">100</span><span class="pln">
        </span><span class="com"># تمكين زر طرح السؤال</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">ask_button</span><span class="pun">[</span><span class="str">"state"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="pln">NORMAL</span></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="145753" href="https://academy.hsoub.com/uploads/monthly_2024_03/1183373785_.png.6462766dd3146d094cd9e148026bf9d4.png" rel=""><img alt="تفعيل زر طرح السؤال" class="ipsImage ipsImage_thumbnailed" data-fileid="145753" data-ratio="91.00" data-unique="04l08njb1" style="width: 500px; height: auto;" width="500" src="https://academy.hsoub.com/uploads/monthly_2024_03/.thumb.png.9b0ef31f626bfaf5941d359c9fb20061.png"> </a>
</p>

<p>
	الخطوة التالية والأخيرة هي تعريف التابع <code>ask_question</code> وهو أهم تابع في تطبيقنا وسنستدعيه بعد كتابة السؤال والنقر على زر طرح السؤال، ليبدأ بالبحث عن إجابة مناسبة على السؤال من محتوى المتغير <code>doc</code> ويرسل الطلب لواجهة OpenAI لتقديم إجابة مناسبة.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4718_33" style=""><span class="kwd">def</span><span class="pln"> ask_question</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
        user_question </span><span class="pun">=</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">question_entry</span><span class="pun">.</span><span class="pln">get</span><span class="pun">()</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> user_question</span><span class="pun">:</span><span class="pln">
                llm </span><span class="pun">=</span><span class="pln"> </span><span class="typ">OpenAI</span><span class="pun">(</span><span class="pln">model</span><span class="pun">=</span><span class="str">"gpt-3.5-turbo-instruct"</span><span class="pun">,</span><span class="pln"> api_key</span><span class="pun">=</span><span class="pln">openai_api_key</span><span class="pun">,</span><span class="pln"> temperature</span><span class="pun">=</span><span class="lit">0.0</span><span class="pun">)</span><span class="pln">
            chain </span><span class="pun">=</span><span class="pln"> load_qa_chain</span><span class="pun">(</span><span class="pln">llm</span><span class="pun">,</span><span class="pln"> chain_type</span><span class="pun">=</span><span class="str">"stuff"</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">with</span><span class="pln"> get_openai_callback</span><span class="pun">():</span><span class="pln">
                response </span><span class="pun">=</span><span class="pln"> chain</span><span class="pun">.</span><span class="pln">run</span><span class="pun">(</span><span class="pln">input_documents</span><span class="pun">=</span><span class="pln">self</span><span class="pun">.</span><span class="pln">docs</span><span class="pun">,</span><span class="pln"> question</span><span class="pun">=</span><span class="pln">user_question</span><span class="pun">)</span><span class="pln">
                </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">response</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">result_text</span><span class="pun">.</span><span class="pln">tag_configure</span><span class="pun">(</span><span class="str">"center"</span><span class="pun">,</span><span class="pln"> justify</span><span class="pun">=</span><span class="str">"center"</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">result_text</span><span class="pun">.</span><span class="pln">delete</span><span class="pun">(</span><span class="str">"1.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">
                self</span><span class="pun">.</span><span class="pln">result_text</span><span class="pun">.</span><span class="pln">insert</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"> response</span><span class="pun">,</span><span class="pln"> </span><span class="str">"center"</span><span class="pun">)</span></pre>

<p>
	كما هو موضح في الكود أعلاه سيحصل التابع على نص السؤال الذي أدخله المستخدم في الحقل النصي <code>question_entry</code> ثم يخزنه في المتغير <code>user_question</code> ويمرر مدخلات المستخدم إلى النموذج gpt-3.5-turbo-instruct لتوليد الإجابة، وهنا نحتاج كذلك لإدخال قيمة المفتاح <code>openai_api_key</code> لإنشاء اتصال مع واجهة برمجة تطبيقات OpenAI ولتخصيص أي وسطاء نحتاجها لتخصيص إجابة النموذج وأهم هذه الوسطاء <code>temperature</code> الذي يحدد درجة دقة السؤال. ويفضل في حالة تطبيقنا أن تبقى قيمته صفر للحصول على إجابات منطقية وحتمية تلتزم بمحتوى الملف، وعدم ترك النموذج يبدع ويؤلف إجابات لا صلة لها بالسياق وسنوضح المزيد عنه لاحقًا عن تجربة تنفيذ التطبيق.
</p>

<p>
	بعدها نستدعي الدالة <code>load_qa_chain</code> التي تنشئ سلسلةً نصيةً من نوع stuff لترسلها كمطالبة إلى الواجهة البرمجية OpenAI التي تفهم بدورها الطلب الذي أرسلناه وتعيد لنا الإجابة المناسبة <code>response</code>. ملاحظة: يحدد نوع السلسلة <code>chain_type</code> طريقة تمرير المستندات إلى النموذج اللغوي الكبير LLM وهنا مررنا القيمة ليكون stuff التي ترسل جميع المستندات في طلب واحد للواجهة البرمجية وهي تناسب حالة التعامل مع مستند واحد أو عدة مستندات صغيرة الحجم وتتضمن نفس طبيعة المحتوى، وهناك طرق أخرى هي<br>
	Map-reduce تفيد في حال التعامل مع مستندات كبيرة هي تلخص كل مستند على حدا ثم تجمع التلخيصات في ملخص نهائي.
</p>

<p>
	أخيرًا نكتب كود تشغيل التطبيق كبرنامج رئيسي من خلال تحميل بيانات مفتاح OpenAI <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> من ملف <code>‎.‎env</code> وفحص فيما إذا كان المفتاح قد تم تعيينه أم لا، والبدء بإنشاء واجهة المستخدم الرسومية وتشغيل التطبيق حتى يتم إغلاق النافذة.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4718_35" 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">
    load_dotenv</span><span class="pun">()</span><span class="pln">
    openai_api_key </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">getenv</span><span class="pun">(</span><span class="str">"OPENAI_API_KEY"</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> openai_api_key </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">None</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">"OpenAI API تأكد من تعيين قيمة مفتاح"</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">
        root </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">
        app </span><span class="pun">=</span><span class="pln"> askpdfgui</span><span class="pun">(</span><span class="pln">root</span><span class="pun">)</span><span class="pln">
        root</span><span class="pun">.</span><span class="pln">mainloop</span><span class="pun">()</span></pre>

<h2 id="-5">
	تجربة عمل التطبيق
</h2>

<p>
	لننفذ الآن كود التطبيق ونختبر آلية عمله: انتقل لمسار وجود التطبيق واكتب الأمر <code>python ask_pdf.py</code> في سطر الأوامر أو الطرفية لتشغيله، ستظهر لك الواجهة الأولية ولتجربة التطبيق سأنقر على زر "حمل ملفك هنا"
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="PNG" data-fileid="145750" href="https://academy.hsoub.com/uploads/monthly_2024_03/pdf.PNG.a3155a2883146311d18ec57c4c404266.PNG" rel=""><img alt="الواجهة الأولية لتطبيق اسأل pdf" class="ipsImage ipsImage_thumbnailed" data-fileid="145750" data-ratio="91.00" data-unique="du5fljb1k" style="width: 500px; height: auto;" width="500" src="https://academy.hsoub.com/uploads/monthly_2024_03/pdf.thumb.PNG.c478ee00cae3f76bb91c48411d9d3782.PNG"> </a>
</p>

<p>
	يمكن تحميل أي ملف pdf خاص بك في التطبيق، وفي حالتي سأختار ملف يتحدث عن <a href="https://academy.hsoub.com/programming/artificial-intelligence/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%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>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="145752" href="https://academy.hsoub.com/uploads/monthly_2024_03/pdf.png.abf02e3e72e26092d89b590e1a98de2c.png" rel=""><img alt="تحميل ملف pdf" class="ipsImage ipsImage_thumbnailed" data-fileid="145752" data-ratio="68.50" data-unique="v1o0wqx1q" style="width: 600px; height: auto;" width="600" src="https://academy.hsoub.com/uploads/monthly_2024_03/pdf.thumb.png.f3fbed640c1ed3298419ba469d14f34a.png"> </a>
</p>

<p>
	بعد اكتمال عملية التحميل سأطرح السؤال التالي: "ما هي لغات برمجة الذكاء الاصطناعي؟" وسأحصل على الإجابة كما هو موضح في الصورة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="145762" href="https://academy.hsoub.com/uploads/monthly_2024_03/ASKpdf2.png.911d27e14d7c26d577d254913c7000f2.png" rel=""><img alt="واجهة تطبيق askpdf 2" class="ipsImage ipsImage_thumbnailed" data-fileid="145762" data-ratio="91.80" data-unique="blz5e8eun" style="width: 500px; height: auto;" width="500" src="https://academy.hsoub.com/uploads/monthly_2024_03/ASKpdf2.thumb.png.46a3d57fc7d00facf5b8f224da80033d.png"> </a>
</p>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="145763" href="https://academy.hsoub.com/uploads/monthly_2024_03/ASKpdf3.png.1e78fbe1191ba33cd2714df6a000dab1.png" rel=""><img alt="واجهة تطبيق askpdf 3" class="ipsImage ipsImage_thumbnailed" data-fileid="145763" data-ratio="91.80" data-unique="n6e5hroky" style="width: 500px; height: auto;" width="500" src="https://academy.hsoub.com/uploads/monthly_2024_03/ASKpdf3.thumb.png.b407bc16c2c5af19c0947ee19e067f17.png"> </a>
</p>

<p>
	الآن لو طرحت سؤالًا لا علاقة له بمحتوى هذا الملف مثل "من اخترع المصباح الكهربائي" ستكون النتيجة كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="145764" href="https://academy.hsoub.com/uploads/monthly_2024_03/askpdf4.png.73fcf7569dd36bf9129f24cb3abbcc61.png" rel=""><img alt="واجهة تطبيق askpdf 4" class="ipsImage ipsImage_thumbnailed" data-fileid="145764" data-ratio="91.80" data-unique="fmhsdttbv" style="width: 500px; height: auto;" width="500" src="https://academy.hsoub.com/uploads/monthly_2024_03/askpdf4.thumb.png.44923447cc05adb83e48ca4c5ed4874d.png"> </a>
</p>

<h2 id="temperature">
	تأثير الوسيط Temperature على دقة نتائج التطبيق
</h2>

<p>
	يستخدم المعامل أو الوسيط <code>temperature</code> كما وضحت سابقًا للتحكم في دقة أو عشوائية النتائج التي تعيدها نماذج واجهة برمجة تطبيقات OpenAI وتتراوح قيمة هذا الوسيط بين 0 و 2، فعند ضبط درجة الدقة على قيم قريبة من الصفر ستحصل على نتائج واقعية وذات صلة بالطلب وحين تضبطه على قيم قريبة من 2 ستحصل على نتائج أكثر إبداعًا لكنها قد تكون غير دقيقة ولا صلة لها بالسؤال. لذا عليك تعديل قيمة هذا المعامل بما يتناسب مع طبيعة تطبيقك، وهل يحتاج للدقة كما في حال تطبيقنا الذي يبحث عن النتائج الموافقة للسؤال، أم يسمح فيه الإبداع والابتكار كتطبيقات تأليف القصص والروايات. سأجرب على سبيل المثال تغير درجة الحرارة في الكود السابق وجعلها مثلًا 1.5 وأحمّل الملف نفسه واطرح سؤال "من هو أديسون؟" مثلًا ستكون النتيجة غير منطقية كما يلي!
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="PNG" data-fileid="145756" href="https://academy.hsoub.com/uploads/monthly_2024_03/940141419_.PNG.d3a650117d9caf149f072a8ca583e23a.PNG" rel=""><img alt="درجة حرارة مرتفعة" class="ipsImage ipsImage_thumbnailed" data-fileid="145756" data-ratio="91.20" data-unique="6jb3o5xe9" style="width: 500px; height: auto;" width="500" src="https://academy.hsoub.com/uploads/monthly_2024_03/.thumb.PNG.062e4fb74e83380dbac5bf67fbff1ff5.PNG"> </a>
</p>

<p>
	أما عند إعادة ضبطه بالقيمة 0 فسيجيب التطبيق بأنه لا يملك معلومات عن أديسون وفق الملف الذي وفرته له.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="145757" href="https://academy.hsoub.com/uploads/monthly_2024_03/941928461_.png.1392802650a083c2813f80c1c0550ce3.png" rel=""><img alt="درجة حرارة منخفضة" class="ipsImage ipsImage_thumbnailed" data-fileid="145757" data-ratio="91.40" data-unique="p50evnw2e" style="width: 500px; height: auto;" width="500" src="https://academy.hsoub.com/uploads/monthly_2024_03/.thumb.png.eb8fb5dacfb32343b5727c06d79f28f1.png"> </a>
</p>

<h2 id="tokens">
	قيود على عدد الرموز Tokens في التطبيق
</h2>

<p>
	يمكنك تجربة التطبيق على أي ملف pdf خاص بك، لكن تملك نماذج من OpenAI <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> حدًا أقصى لعدد الرموز Token Limits التي تمثل إجمالي طول المدخلات التي تستقبلها والنتائج التي تولدها وفي حالة النموذج gpt-3.5-turbo-instruct المستخدم في الكود فالعدد الأقصى هو 4096 رمزًا، وبالتالي قد تحصل على الخطأ التالي عند تحميل ملفات كبيرة وتجاوز إجمالي الرموز في دخل وخرج النموذج هذا العدد، ومن الإجراءات الممكنة لتجاوز هذه القيود، تحديد قيمة المعامل <code>max_tokens</code> للنموذج كي تحدد له طول الرد الذي سينتج وتمنعه من إنشاء محتوى طويل جدًا أو تقصير نص الطلب أو السؤال قدر المستطاع.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="PNG" data-fileid="145754" href="https://academy.hsoub.com/uploads/monthly_2024_03/1.PNG.9b803760956f99967fa610274a7c916a.PNG" rel=""><img alt="خطأ واجهة1" class="ipsImage ipsImage_thumbnailed" data-fileid="145754" data-unique="7uzszle4g" src="https://academy.hsoub.com/uploads/monthly_2024_03/1.thumb.PNG.2fd6c77e7ab2e1c24059e3db8e7c0d67.PNG"> </a>
</p>

<p>
	كما تحدد بعض النماذج سرعة معالجة الرموز في الدقيقة الواحدة، فالحد الأقصى المسموح به للتضمينات في نموذج text-embedding-ada-002 هو 15000 رمز في الدقيقة، وبالتالي إذا استخدمت ملفات pdf كبيرة تتجاوز هذه الحدود فسوف تحصل على كذلك أخطاء في التنفيذ بسبب القيود التي تفرضها الواجهة البرمجية ولحلها عليك رفع خطة الاشتراك في الواجهة البرمجية.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="PNG" data-fileid="145755" href="https://academy.hsoub.com/uploads/monthly_2024_03/2.PNG.89ea2cdcf3161d18843f51af691e2b9c.PNG" rel=""><img alt="خطأ واجهة2" class="ipsImage ipsImage_thumbnailed" data-fileid="145755" data-unique="2gge89uqt" src="https://academy.hsoub.com/uploads/monthly_2024_03/2.thumb.PNG.e60033f1ff961f532856527079c543be.PNG"> </a>
</p>

<h2 id="-6">
	الخلاصة
</h2>

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

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

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/php/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D8%B5%D9%81%D8%A9-%D9%84%D8%A7%D9%82%D8%AA%D8%B1%D8%A7%D8%AD-%D8%A7%D9%84%D9%88%D8%AC%D8%A8%D8%A7%D8%AA-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-chatgpt-%D9%88-dall-e-%D9%81%D9%8A-php-r2005/" rel="">تطوير تطبيق "وصفة" لاقتراح الوجبات باستخدام ChatGPT و DALL-E في PHP</a>
	</li>
	<li>
		<a 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%A7%D8%AE%D8%AA%D8%A8%D8%B1%D9%86%D9%8A-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-chatgpt-%D9%88%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-%D9%85%D8%B9-nodejs-r2018/" rel="">تطوير تطبيق "اختبرني" باستخدام ChatGPT ولغة جافاسكربت مع Node.js</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%84%D9%84%D9%85%D8%B4%D8%A7%D8%B1%D9%8A%D8%B9-%D9%85%D8%B9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1751/" rel="">إعداد بيئة العمل للمشاريع مع بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%83%D8%AA%D8%B4%D8%A7%D9%81-%D8%AF%D9%84%D8%A7%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D9%81%D9%8A-%D8%B4%D9%8A%D9%81%D8%B1%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1944/" rel="">اكتشاف دلالات الأخطاء في شيفرات لغة بايثون</a>
	</li>
</ul>

<p>
	كود التطبيق
</p>

<p>
	<a class="ipsAttachLink" data-fileext="zip" data-fileid="145774" data-filekey="cf5dda9a67ab15278c219657c518d35f" href="https://academy.hsoub.com/applications/core/interface/file/attachment.php?id=145774&amp;key=cf5dda9a67ab15278c219657c518d35f" rel="">ask_pdf.zip</a>
</p>
]]></description><guid isPermaLink="false">2265</guid><pubDate>Tue, 05 Mar 2024 12: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; &#x641;&#x64A; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646;: &#x627;&#x644;&#x62A;&#x648;&#x627;&#x628;&#x639; &#x627;&#x644;&#x633;&#x62D;&#x631;&#x64A;&#x629; &#x627;&#x644;&#x645;&#x648;&#x636;&#x639;&#x64A;&#x629; In-place Dunder Methods</title><link>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-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%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-%D8%A7%D9%84%D9%85%D9%88%D8%B6%D8%B9%D9%8A%D8%A9-in-place-dunder-methods-r2204/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_12/--Dunder-Methods-----place-in---Python.png.951f317f54285b7b1acb0c3a8c6c2875.png" /></p>
<p>
	ننشئ التوابع السحرية العددية والمعكوسة <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-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%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-dunder-methods-r2192/" rel="">كما رأينا سابقًا</a> كائنات جديدة بدلًا من تعديل الكائنات الموضعية، إلا أن التوابع السحرية الموضعية المُستدعاة باستخدام معاملات الإسناد المدعوم مثل <code>=+</code> و <code>=*</code> تعدل الكائنات موضعيًا بدلًا من إنشاء كائنات جديدة (هناك استثناء سنشرحه في نهاية الفقرة). تبدأ أسماء هذه التوابع السحرية بحرف<em>i</em>، مثل <code>()__iadd__</code> و <code>()__imul__</code> من أجل العوامل <code>=+</code> و <code>=*</code> على التتالي.
</p>

<p>
	مثلًا، عندما تنفذ بايثون الشيفرة <code>purse *= 2</code> لا يكون السلوك المتوقع أن تابع <code>()__imul__</code> الخاص بالصنف <code>WizCoin</code> سينشئ ويعيد كائن <code>WizCoin</code> جديد بضعف عدد النقود ويسنده للمتغير <code>purse</code>، ولكن بدلًا من ذلك، يعدل التابع <code>()__imul__</code> كائن <code>WizCoin</code> الحالي في <code>purse</code> ليكون له ضعف عدد النقود. هذا فرق بسيط ولكن مهم إذا أردت لأصنافك أن تقوم بتحميل زائد overload لمعاملات الإسناد المدعومة.
</p>

<p>
	عرّف الصنف 'WizCoin' الذي أنشأناه العاملين <code>+</code> و <code>*</code>، لذا لنُعرّف التابعين السحريين <code>()__iadd__</code> و <code>()__imul__</code> ليتمكّنوا بدورهم من تعريف العاملين <code>=+</code> و <code>=*</code> أيضًا، نستدعي في التعبيرين <code>purse += tipJar</code> و <code>purse *= 2</code> التابعين <code>()__iadd__</code> و <code>()__imul__</code> على التتالي وتمرر <code>tipJar</code> و <code>2</code> إلى المعامل <code>other</code> على التتالي.
</p>

<p>
	ضِف التالي إلى نهاية ملف <strong>wizcoin.py</strong>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8247_6" style=""><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">
    </span><span class="kwd">def</span><span class="pln"> __iadd__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">):</span><span class="pln">
        </span><span class="str">"""Add the amounts in another WizCoin object to this object."""</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> isinstance</span><span class="pun">(</span><span class="pln">other</span><span class="pun">,</span><span class="pln"> </span><span class="typ">WizCoin</span><span class="pun">):</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">NotImplemented</span><span class="pln">

        </span><span class="com"># نعدل من قيمة الكائن‫ self موضعيًا</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">galleons </span><span class="pun">+=</span><span class="pln"> other</span><span class="pun">.</span><span class="pln">galleons
        self</span><span class="pun">.</span><span class="pln">sickles </span><span class="pun">+=</span><span class="pln"> other</span><span class="pun">.</span><span class="pln">sickles
        self</span><span class="pun">.</span><span class="pln">knuts </span><span class="pun">+=</span><span class="pln"> other</span><span class="pun">.</span><span class="pln">knuts
        </span><span class="kwd">return</span><span class="pln"> self  </span><span class="com"># تعيد التوابع السحرية الموضعية القيمة‫ self على الدوام تقريبًا</span><span class="pln">

    </span><span class="kwd">def</span><span class="pln"> __imul__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">):</span><span class="pln">
        </span><span class="str">"""Multiply the amount of galleons, sickles, and knuts in this object
        by a non-negative integer amount."""</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> isinstance</span><span class="pun">(</span><span class="pln">other</span><span class="pun">,</span><span class="pln"> int</span><span class="pun">):</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">NotImplemented</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> other </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">raise</span><span class="pln"> </span><span class="typ">WizCoinException</span><span class="pun">(</span><span class="str">'cannot multiply with negative integers'</span><span class="pun">)</span><span class="pln">

        </span><span class="com"># يُنشئ الصنف‫ WizCoin كائنات متغيّرة، لذا لا تنشئ كائن جديد كما هو موضح في الشيفرة المعلّقة:</span><span class="pln">
        </span><span class="com">#return WizCoin(self.galleons * other, self.sickles * other, self.knuts * other)</span><span class="pln">

        </span><span class="com"># نعدل من قيمة الكائن‫ self موضعيًا</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">galleons </span><span class="pun">*=</span><span class="pln"> other
        self</span><span class="pun">.</span><span class="pln">sickles </span><span class="pun">*=</span><span class="pln"> other
        self</span><span class="pun">.</span><span class="pln">knuts </span><span class="pun">*=</span><span class="pln"> other
        </span><span class="kwd">return</span><span class="pln"> self  </span><span class="com">#  تعيد التوابع السحرية الموضعية القيمة‫ self دائمًا تقريبًا</span></pre>

<p>
	يمكن أن تستخدم كائنات <code>WizCoin</code> العامل <code>=+</code> مع كائنات <code>WizCoin</code> أخرى والعامل <code>‎=*</code> مع الأعداد الصحيحة الموجبة. تعدّل التوابع الموضعية الكائن 'self' موضعيًا بدلًا من إنشاء كائن 'WizCoin' جديد بعد التأكد من أن المعامل الآخر صالح. أدخل التالي إلى الصدفة التفاعلية لرؤية كيف تعدل عوامل الإسناد المدعوم كائنات <code>WizCoin</code> موضعيًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8247_8" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> wizcoin
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">=</span><span class="pln"> wizcoin</span><span class="pun">.</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> tipJar </span><span class="pun">=</span><span class="pln"> wizcoin</span><span class="pun">.</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">37</span><span class="pun">)</span><span class="pln">
</span><span class="lit">1</span><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">+</span><span class="pln"> tipJar
</span><span class="lit">2</span><span class="pln"> </span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">46</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse
</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln">
</span><span class="lit">3</span><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">+=</span><span class="pln"> tipJar
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse
</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">47</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"> purse </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"> purse
</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">20</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln"> </span><span class="lit">470</span><span class="pun">)</span></pre>

<p>
	يستدعي العامل <code>+</code> التابعين السحريين <code>()__add__</code> و <code>()__radd__</code> لإنشاء وإعادة كائنات جديدة. تبقى الكائنات الأصلية التي يعمل عليها العامل <code>+</code> على حالها. يجب على التوابع السحرية الموضعية أن تعدل الكائنات موضعيًا طالما أن الكائن <a href="https://academy.hsoub.com/programming/python/%D9%85%D8%B5%D8%B7%D9%84%D8%AD%D8%A7%D8%AA-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1982/" rel="">متغيّر mutable</a> (أي هو كائن يمكن تغيير قيمته). الاستثناء هو للكائنات الثابتة immutable objects، إذ لا يمكن تعديلها ومن المستحيل تعديلها موضعيًا. في هذه الحالة يجب على التابع السحري الموضعي إنشاء وإعادة كائن جديد كما في التوابع السحرية العددية والمعكوسة.
</p>

<p>
	إذا لم نجعل السمات <code>galleons</code> و <code>sickles</code> و <code>knuts</code> للقراءة فقط، فهذا يعني أنه يمكن تعديلها، وبالتالي كائنات <code>WizCoin</code> هي متغيّرة، كما أن معظم الأصناف التي تكتبه تُنشئ كائنات متغيّرة لذا يجب تصميم توابع سحرية موضعية لتعديل الكائن موضعيًا.
</p>

<p>
	تستدعي بايثون تلقائيًا التابع السحري العددي في حال لم تُنفذ التابع السحري الموضعي. مثلًا، إذا لم يكن للصنف <code>WizCoin</code> تابع <code>()__imul__</code> سيستدعي التعبير <code>purse *= 10</code> التابع <code>()__mul__</code> بدلًا عنه ويسند له القيمة المرجعة <code>purse</code>، لأن كائنات <code>WizCoin</code> متغيّرة وهذا سلوك غير متوقع وقد يؤدي لأخطاء بسيطة.
</p>

<h2 id="">
	توابع المقارنة السحرية
</h2>

<p>
	يحتوي تابع <code>‎‎sort‎‎‎‎‎()‎‎‎</code> ودالة <code>sorted()‎‎‏‏</code> <a href="https://wiki.hsoub.com/Algorithms/Sorting_Algorithms" rel="external">خوارزميات ترتيب</a> فعالة، ويمكن الوصول إليها باستدعاء بسيط، ولكن إذا أردت ترتيب ومقارنة كائنات أصنافك، ستحتاج لإخبار بايثون كيفية المقارنة بين الكائنين عن طريق تنفيذ توابع المقارنة السحرية، تستدعي بايثون التوابع المقارنة في الخلفية عندما تُستخدم الكائنات الخاصة بك في التعبير مع <a href="https://wiki.hsoub.com/Python/comparisons" rel="external">عوامل المقارنة</a><code>&lt;</code> و <code>&gt;</code> و <code>=&lt;</code> و <code>=&gt;</code> و <code>==</code> و <code>=!</code>.
</p>

<p>
	قبل أن نستكشف توابع المقارنة السحرية، فلنفحص الدوال الست في <a href="https://wiki.hsoub.com/Python/operator" rel="external">وحدة 'operator'</a> التي تنجز نفس وظائف عوامل المُقارنة الستة، إذ ستستدعي توابع المقارنة السحرية هذه الدوال. أدخل التالي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8247_10" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> operator
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> operator</span><span class="pun">.</span><span class="pln">eq</span><span class="pun">(</span><span class="lit">42</span><span class="pun">,</span><span class="pln"> </span><span class="lit">42</span><span class="pun">)</span><span class="pln">        </span><span class="com"># أي يساوي، وهي مماثلة للتعبير 42 == 42</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> operator</span><span class="pun">.</span><span class="pln">ne</span><span class="pun">(</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dog'</span><span class="pun">)</span><span class="pln">  </span><span class="com"># أي لا يساوي وهي مماثلة للتعبير‫ 'cat' != 'dog'</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> operator</span><span class="pun">.</span><span class="pln">gt</span><span class="pun">(</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">20</span><span class="pun">)</span><span class="pln">        </span><span class="com"># أكبر من، وهي مماثلة للتعبير 20 &lt; 10</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> operator</span><span class="pun">.</span><span class="pln">ge</span><span class="pun">(</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln">        </span><span class="com"># أكبر من أو يساوي، وهي مماثلة للتعبير 10 =&lt; 10</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> operator</span><span class="pun">.</span><span class="pln">lt</span><span class="pun">(</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">20</span><span class="pun">)</span><span class="pln">        </span><span class="com"># أصغر من، وهي مماثلة للتعبير 20 &gt; 10</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> operator</span><span class="pun">.</span><span class="pln">le</span><span class="pun">(</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">20</span><span class="pun">)</span><span class="pln">        </span><span class="com"># أصغر من أو يساوي وهي مماثلة للتعبير 10 =&gt; 20</span><span class="pln">
</span><span class="kwd">True</span></pre>

<p>
	ستعطينا وحدة <code>operator</code> نسخ دوال من عوامل المقارنة ويكون تنفيذها بسيط. مثلًا يمكننا كتابة دالة <code>operator.eq()‎</code> في سطرين:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8247_12" style=""><span class="kwd">def</span><span class="pln"> eq</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> a </span><span class="pun">==</span><span class="pln"> b</span></pre>

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

<p>
	أولًا، ضِف التالي إلى بداية الملف <strong>wizcoin.py</strong>، إذ تعطي تعليمات الاستيراد <code>import</code> هذه الإذن بالوصول للدوال في وحدة <code>operator</code> وتسمح لك بالتحقق أن الوسيط <code>other</code> في التابع هو متتالية sequence عن طريق مقارنته مع <code>collections.abc.Sequence</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8247_14" style=""><span class="kwd">import</span><span class="pln"> collections</span><span class="pun">.</span><span class="pln">abc
</span><span class="kwd">import</span><span class="pln"> operator</span></pre>

<p>
	ثم ضِف التالي في نهاية ملف <strong>wizcoin.py</strong>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8247_20" style=""><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">
</span><span class="lit">1</span><span class="pln">     </span><span class="kwd">def</span><span class="pln"> _comparisonOperatorHelper</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> operatorFunc</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">):</span><span class="pln">
        </span><span class="str">"""A helper method for our comparison dunder methods."""</span><span class="pln">

</span><span class="lit">2</span><span class="pln">         </span><span class="kwd">if</span><span class="pln"> isinstance</span><span class="pun">(</span><span class="pln">other</span><span class="pun">,</span><span class="pln"> </span><span class="typ">WizCoin</span><span class="pun">):</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> operatorFunc</span><span class="pun">(</span><span class="pln">self</span><span class="pun">.</span><span class="pln">total</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">.</span><span class="pln">total</span><span class="pun">)</span><span class="pln">
</span><span class="lit">3</span><span class="pln">         </span><span class="kwd">elif</span><span class="pln"> isinstance</span><span class="pun">(</span><span class="pln">other</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">int</span><span class="pun">,</span><span class="pln"> float</span><span class="pun">)):</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> operatorFunc</span><span class="pun">(</span><span class="pln">self</span><span class="pun">.</span><span class="pln">total</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">)</span><span class="pln">
</span><span class="lit">4</span><span class="pln">         </span><span class="kwd">elif</span><span class="pln"> isinstance</span><span class="pun">(</span><span class="pln">other</span><span class="pun">,</span><span class="pln"> collections</span><span class="pun">.</span><span class="pln">abc</span><span class="pun">.</span><span class="typ">Sequence</span><span class="pun">):</span><span class="pln">
            otherValue </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">other</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</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><span class="pln"> </span><span class="lit">29</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="pln">other</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="lit">29</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> other</span><span class="pun">[</span><span class="lit">2</span><span class="pun">]</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> operatorFunc</span><span class="pun">(</span><span class="pln">self</span><span class="pun">.</span><span class="pln">total</span><span class="pun">,</span><span class="pln"> otherValue</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">elif</span><span class="pln"> operatorFunc </span><span class="pun">==</span><span class="pln"> operator</span><span class="pun">.</span><span class="pln">eq</span><span class="pun">:</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">
        </span><span class="kwd">elif</span><span class="pln"> operatorFunc </span><span class="pun">==</span><span class="pln"> operator</span><span class="pun">.</span><span class="pln">ne</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="kwd">else</span><span class="pun">:</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">NotImplemented</span><span class="pln">

    </span><span class="kwd">def</span><span class="pln"> __eq__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">):</span><span class="pln">  </span><span class="com"># eq is "EQual"</span><span class="pln">
</span><span class="lit">5</span><span class="pln">         </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">_comparisonOperatorHelper</span><span class="pun">(</span><span class="pln">operator</span><span class="pun">.</span><span class="pln">eq</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">def</span><span class="pln"> __ne__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">):</span><span class="pln">  </span><span class="com"># ne is "Not Equal"</span><span class="pln">
</span><span class="lit">6</span><span class="pln">         </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">_comparisonOperatorHelper</span><span class="pun">(</span><span class="pln">operator</span><span class="pun">.</span><span class="pln">ne</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">def</span><span class="pln"> __lt__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">):</span><span class="pln">  </span><span class="com"># lt is "Less Than"</span><span class="pln">
</span><span class="lit">7</span><span class="pln">         </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">_comparisonOperatorHelper</span><span class="pun">(</span><span class="pln">operator</span><span class="pun">.</span><span class="pln">lt</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">def</span><span class="pln"> __le__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">):</span><span class="pln">  </span><span class="com"># le is "Less than or Equal"</span><span class="pln">
</span><span class="lit">8</span><span class="pln">         </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">_comparisonOperatorHelper</span><span class="pun">(</span><span class="pln">operator</span><span class="pun">.</span><span class="pln">le</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">def</span><span class="pln"> __gt__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">):</span><span class="pln">  </span><span class="com"># gt is "Greater Than"</span><span class="pln">
</span><span class="lit">9</span><span class="pln">        </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">_comparisonOperatorHelper</span><span class="pun">(</span><span class="pln">operator</span><span class="pun">.</span><span class="pln">gt</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">def</span><span class="pln"> __ge__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">):</span><span class="pln">  </span><span class="com"># ge is "Greater than or Equal"</span><span class="pln">
a        </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">_comparisonOperatorHelper</span><span class="pun">(</span><span class="pln">operator</span><span class="pun">.</span><span class="pln">ge</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">)</span></pre>

<p>
	تستدعي توابع المقارنة السحرية التابع <code>‎__comparisonOperatorHelper()‎</code> وتمرر الدالة المناسبة من وحدة <code>operator</code> إلى المعامل <code>operatorFunc</code>، عند استدعاء <code>operatorFunc()‎</code> فنحن هنا نستدعي الدالة المُمرّرة إلى معامل <code>operatorFunc</code> الذي هو <code>eq()‎</code> أو <code>ne()‎</code> أو <code>lt()‎</code> أو <code>le()‎</code> أو <code>gt()‎</code> أو <code>ge()‎</code> من وحدة <code>operator</code>، أو سيكون علينا تكرار الشيفرة في <code>‎__comparisonOperatorHelper()‎</code> في كل من توابع المقارنة السحرية الستة.
</p>

<p>
	ملاحظة: تدعى الدوال (أو التوابع) التي تقبل دوال أخرى على أنها وسطاء، مثل <code>‎__comparisonOperatorHelper()‎</code> بدوال المراتب الأعلى higher-order functions.
</p>

<p>
	يمكن الآن مقارنة كائنات <code>WizCoin</code> مع كائنات <code>WizCoin</code> أخرى و<a href="https://wiki.hsoub.com/Python/int" rel="external">أعداد صحيحة</a> و<a href="https://wiki.hsoub.com/Python/float" rel="external">عشرية</a> وقيم سلسلة من ثلاث قيم عددية تمثل galleons و sickles و knuts. أدخل التالي في الصدفة التفاعلية لرؤية الأمر عمليًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8247_18" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> wizcoin
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">=</span><span class="pln"> wizcoin</span><span class="pun">.</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln">  </span><span class="com"># إنشاء كائن‫ WizCoin</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> tipJar </span><span class="pun">=</span><span class="pln"> wizcoin</span><span class="pun">.</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">37</span><span class="pun">)</span><span class="pln"> </span><span class="com"># إنشاء كائن‫ WizCoin آخر</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse</span><span class="pun">.</span><span class="pln">total</span><span class="pun">,</span><span class="pln"> tipJar</span><span class="pun">.</span><span class="pln">total </span><span class="com"># فحص القيم وفقًا إلى‫ knuts</span><span class="pln">
</span><span class="pun">(</span><span class="lit">1141</span><span class="pun">,</span><span class="pln"> </span><span class="lit">37</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">&gt;</span><span class="pln"> tipJar </span><span class="com"># ‫المقارنة بين كائنات WizCoin باستخدام عامل مقارنة</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">&lt;</span><span class="pln"> tipJar
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">1000</span><span class="pln"> </span><span class="com"># الموازنة مع عدد صحيح</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">1000</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1141</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1141.0</span><span class="pln"> </span><span class="com"># المقارنة مع عدد عشري</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">==</span><span class="pln"> </span><span class="str">'1141'</span><span class="pln"> </span><span class="com"># ‫كائن WizCoin ليس مساويًا لأي قيمة سلسلة نصية</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> bagOfKnuts </span><span class="pun">=</span><span class="pln"> wizcoin</span><span class="pun">.</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1141</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">==</span><span class="pln"> bagOfKnuts
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">==</span><span class="pln"> </span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> </span><span class="com"># يمكننا المقارنة مع صف يتكون من ثلاثة أعداد صحيحة</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">]</span><span class="pln"> </span><span class="com"># يمكننا المقارنة مع قائمة تحتوي على ثلاثة أعداد صحيحة</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'cat'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dog'</span><span class="pun">]</span><span class="pln"> </span><span class="com"># يجب أن تتسبب هذه التعليمة بخطأ</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;stdin&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"C:\Users\Al\Desktop\wizcoin.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">265</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> __ge__
    </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">_comparisonOperatorHelper</span><span class="pun">(</span><span class="pln">operator</span><span class="pun">.</span><span class="pln">ge</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">)</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"C:\Users\Al\Desktop\wizcoin.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">237</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> _comparisonOperatorHelper
    otherValue </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">other</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</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><span class="pln"> </span><span class="lit">29</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="pln">other</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="lit">29</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> other</span><span class="pun">[</span><span class="lit">2</span><span class="pun">]</span><span class="pln">
</span><span class="typ">IndexError</span><span class="pun">:</span><span class="pln"> list index out of range</span></pre>

<p>
	يستدعي التابع المساعد <code>isinstance(other, collections.abc.Sequence)‎</code> لرؤية ما إذا كان <code>other</code> هو نوع بيانات متتالية مثل <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%B5%D9%81%D9%88%D9%81%D8%8C-%D8%A7%D9%84%D9%85%D8%AC%D9%85%D9%88%D8%B9%D8%A7%D8%AA-%D9%88%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-r226/" rel="">صف tuple</a> أو <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-%D9%88%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-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r223/" rel="">قائمة list</a>. بإمكاننا كتابة شيفرة مثل <code>purse &gt;= [2, 5, 10]‎</code> لعمل مقارنة سريعة، وذلك بجعل كائنات <code>WizCoin</code> قابلة للمقارنة مع متتاليات.
</p>

<h2 id="-1">
	مقارنة المتتاليات
</h2>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8247_22" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Azriel'</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="str">'Zelda'</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8888</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9999</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">True</span></pre>

<p>
	تأتي السلسلة النصية <code>Azriel</code> قبل (أي هي أقل من) <code>Zelda</code> لأن <code>'A'</code> تأتي قبل <code>'Z'</code>. الصف <code>(3, 2, 1)</code> يأتي بعد (أي هو أكبر من) <code>(9999, 8888, 0)</code> لأن <code>1</code> هي أكبر من <code>0</code>. أدخل التالي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8247_24" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'Azriel'</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="str">'Aaron'</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</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">&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9999</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">False</span></pre>

<p>
	لا تأتي <code>Azriel</code> قبل <code>Aaron</code> على الرغم من أن <code>'A'</code> في <code>'Azriel'</code> تساوي <code>'A'</code> في <code>'Aaron'</code> ولكن <code>'z'</code> التالية في <code>'Azriel'</code> لا تأتي قبل <code>'a'</code> في <code>'Aaron'</code>، ويمكن تطبيق الشيء ذاته في الصفين <code>(1, 0, 0)</code> و <code>(1, 0, 9999)</code>، إذ أن العنصرين في كل صف متساويين لذا تحدد العناصر الثالثة (<code>0</code> و <code>9999</code> على التتالي) أن <code>(0, 0, 1)</code> تأتي قبل <code>(9999, 0, 1)</code>.
</p>

<p>
	هذا يجبرنا على اتخاذ قرار بشأن تصميم صنف <code>WizCoin</code> فهل يجب أن تأتي <code>WizCoin(0, 0, 9999)‎</code> قبل أو بعد <code>WizCoin(1, 0, 0)‎</code>؟ إذا كان عدد galleons أهم من عدد sickles أو knuts فيجب على <code>WizCoin(0, 0, 9999)‎</code> أن تأتي قبل <code>WizCoin(1, 0, 0)‎</code>، أما إذا قارننا الكائنات بالاعتماد على قيمة knuts فيجب أن تأتي <code>WizCoin(0, 0, 9999)‎</code> (قيمتها ‎9999 knuts) بعد <code>WizCoin(1, 0, 0)‎</code> (قيمتها 493‎ knuts).وُضعت قيمة الكائن في ملف wzicoin.py على أنها مقدرة بـ knuts لأنها تجعل السلوك متناسقًا مع كيفية مقارنة<code>WizCoin</code> مع الأعداد الصحيحة والعشرية. هذا نوع من الاختيارات التي يجب أن تفعلها عند تصميم الأصناف الخاصة بك.
</p>

<p>
	لا توجد توابع سحرية مقارنة معكوسة مثل <code>()__req__</code> أو <code>()__rne__</code> تحتاج لتنفيذها، وبدلًا عن ذلك نجد أن <code>()__lt__</code> و <code>()__gt__</code> تعكس بعضها و <code>()__le__</code> و <code>()__ge__</code> تعكس بعضها و <code>()__eq__</code> و <code>()__ne__</code> تعكس نفسها، سبب ذلك هو أن العلاقات التالية صحيحة مهما كانت القيم في يمين أو يسار المعامل.
</p>

<ul>
	<li>
		<code>purse &gt; [2, 5, 10]‎</code> هي نفس <code>‎[2, 5, 10] &lt; purse</code>
	</li>
	<li>
		<code>purse &gt;= [2, 5, 10]‎</code> هي نفس <code>‎[2, 5, 10] &lt;= purse</code>
	</li>
	<li>
		<code>purse == [2, 5, 10]‎</code> هي نفس <code>‎[2, 5, 10] == purse</code>
	</li>
	<li>
		<code>purse! = [2, 5, 10]‎</code> هي نفس <code>‎[2, 5, 10] != purse</code>
	</li>
</ul>

<p>
	بمجرد تطبيقك للدوال السحرية المقارنة، ستستخدم بايثون تلقائيًا دالة <code>sort()‎</code> لترتيب الكائنات الخاصة بك. أدخل التالي في الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8247_26" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> wizcoin
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> oneGalleon </span><span class="pun">=</span><span class="pln"> wizcoin</span><span class="pun">.</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</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">#  ‫تكافئ 493 knut</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> oneSickle </span><span class="pun">=</span><span class="pln"> wizcoin</span><span class="pun">.</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">0</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">0</span><span class="pun">)</span><span class="pln">  </span><span class="com">#  ‫تكافئ 29 knut</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> oneKnut </span><span class="pun">=</span><span class="pln"> wizcoin</span><span class="pun">.</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">    </span><span class="com"># ‫تكافئ 1 knut</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> coins </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">oneSickle</span><span class="pun">,</span><span class="pln"> oneKnut</span><span class="pun">,</span><span class="pln"> oneGalleon</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">&gt;&gt;&gt;</span><span class="pln"> coins</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">()</span><span class="pln"> </span><span class="com"># رتّب من القيمة الأقل إلى الأعلى</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> coins
</span><span class="pun">[</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</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">WizCoin</span><span class="pun">(</span><span class="lit">0</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">0</span><span class="pun">),</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)]</span><span class="pln"> </span></pre>

<p>
	يحتوي الجدول 3 قائمة كاملة من توابع المقارنة السحرية ودوال <code>operator</code>.
</p>

<table>
	<thead>
		<tr>
			<th>
				التابع السحري
			</th>
			<th>
				المعامل
			</th>
			<th>
				معامل المقارنة
			</th>
			<th>
				الدالة في وحدة <code>operator</code>
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				<code>()__eq__</code>
			</td>
			<td>
				يساوي
			</td>
			<td>
				<code>==</code>
			</td>
			<td>
				<code>operator.eq()‎</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__ne__</code>
			</td>
			<td>
				لا يساوي
			</td>
			<td>
				<code>=!</code>
			</td>
			<td>
				<code>operator.nt()‎</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__lt__</code>
			</td>
			<td>
				أصغر من
			</td>
			<td>
				<code>&lt;</code>
			</td>
			<td>
				<code>operator.lt()‎</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__le__</code>
			</td>
			<td>
				أصغر أو يساوي
			</td>
			<td>
				<code>=&gt;</code>
			</td>
			<td>
				<code>operator.le()‎</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__gt__</code>
			</td>
			<td>
				أكبر من
			</td>
			<td>
				<code>&lt;</code>
			</td>
			<td>
				<code>operator.gt()‎</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__ge__</code>
			</td>
			<td>
				أكبر أو يساوي
			</td>
			<td>
				<code>=&lt;</code>
			</td>
			<td>
				<code>operator.ge()‎</code>
			</td>
		</tr>
	</tbody>
</table>

<p style="text-align: center;">
	الجدول 3: توابع المقارنة السحرية ودوال وحدة <code>operator</code>.
</p>

<p>
	يمكنك رؤية تطبيق هذه التوابع في <a href="https://autbor.com/wizcoinfull" rel="external nofollow">https://autbor.com/wizcoinfull</a>.
</p>

<p>
	التوثيق الكامل لتوابع المقارنة السحرية في توثيقات بايثون <a href="https://docs.python.org/3/reference/datamodel.html#object.__lt__" rel="external nofollow">https://docs.python.org/3/reference/datamodel.html#object.lt</a>.
</p>

<h2 id="-2">
	الخلاصة
</h2>

<p>
	تسمح توابع المقارنة السحرية لكائنات الأصناف الخاصة بك أن تستخدم معاملات بايثون للمقارنة بدلًا من إجبارك على إنشاء توابع خاصة بك. إذا كنت تُنشئ توابعًا اسمها <code>equals()‎</code> و <code>isGreaterThan()‎</code> فهذه ليست خاصة ببايثون، وعدّ هذه إشارة لك لتبدأ باستخدام توابع المقارنة السحرية.
</p>

<p>
	ترجمة -وبتصرف- لقسم من الفصل <a href="http://inventwithpython.com/beyond/chapter17.html" rel="external nofollow">PYTHONIC <abbr title="Object-Oriented Programming | البرمجة كائنية التوجه"><abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr></abbr>: PROPERTIES AND DUNDER METHODS</a> من كتاب <a href="https://inventwithpython.com/beyond//" rel="external nofollow">Beyond the Basic Stuff with Python</a>.
</p>

<h2 id="-3">
	اقرأ المزيد
</h2>

<ul>
	<li>
		المقال السابق <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-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%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-dunder-methods-r2192/" rel="">البرمجة كائنية التوجه في بايثون: التوابع السحرية Dunder Methods</a>.
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D8%A3%D8%B5%D9%86%D8%A7%D9%81-%D9%88%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-r754/" rel="">كيفية إنشاء الأصناف وتعريف الكائنات في بايثون 3</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/python/%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-%D9%88%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D9%87%D8%A7-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r2012/" rel="">البرمجة الوظيفية Functional Programming وتطبيقها في بايثون</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2204</guid><pubDate>Wed, 20 Dec 2023 05:48: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; &#x641;&#x64A; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646;: &#x627;&#x644;&#x62A;&#x648;&#x627;&#x628;&#x639; &#x627;&#x644;&#x633;&#x62D;&#x631;&#x64A;&#x629; Dunder Methods</title><link>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-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%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-dunder-methods-r2192/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_12/--------Dunder-Methods.png.5aedec75e1e3f7bc07930fb67742eb72.png" /></p>
<p>
	لدى <a href="https://academy.hsoub.com/python/" rel="">لغة بايثون Python</a> أسماء توابع خاصة تبدأ وتنتهي بشرطتين سفليتين وتختصر بالسحرية، وتسمى عادةً التوابع السحرية أو التوابع الخاصة أو توابع داندر Dunder Methods، أنت تعرف مسبقًا اسم التابع السحري <a href="https://wiki.hsoub.com/Python/class_definition#.D8.A7.D9.84.D8.AA.D8.A7.D8.A8.D8.B9_init_.28.29" rel="external"><code>‎__init__()‎</code></a> ولكن لدى بايثون العديد غيره، نستخدمهم عادةً لزيادة تحميل المعامل، أي إضافة سلوكيات خاصة تسمح لنا باستخدام <a href="https://academy.hsoub.com/programming/python/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D8%A3%D8%B5%D9%86%D8%A7%D9%81-%D9%88%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-r754/" rel="">كائنات الأصناف</a> الخاصة بنا مع معاملات بايثون، مثل <code>+</code> أو <code>&gt;=</code>. تسمح التوابع السحرية الأخرى لكائنات الأصناف الخاصة بنا بالعمل مع وظائف بايثون المضمنة مثل <code>len()‎</code> و <code>repe()‎</code>.
</p>

<p>
	كما هي الحال في <code>‎__init__()‎</code> أو توابع الجلب والضبط والحذف، لا نستدعي التوابع السحرية مباشرةً، يل تستدعيهم بايثون في الخلفية عندما تستخدم الكائنات مع المعاملات أو بعض الوظائف المضمنة. مثلًا، إذا أنشأت تابعًا اسمه <code>‎__len__()‎</code> أو <code>‎__repr__()‎</code> للأصناف الخاصة بك فستُستدعى في الخلفية عندما يمرر كائن من هذا الصنف إلى الدالة <code>len()‎</code> أو <code>repr()‎</code> على التوالي. هذه التوابع موثقة على الويب في <a href="https://docs.python.org/3/reference/datamodel.html" rel="external nofollow">توثيقات بايثون الرسمية</a>.
</p>

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

<h2 id="">
	توابع تمثيل السلاسل النصية السحرية
</h2>

<p>
	يمكن استخدام التوابع السحرية <code>‎__repr__()‎</code> و <code>‎__str__()‎</code> لإنشاء سلسلة نصية تمثل كائنات لا تتعامل معها بايثون عادةً، إذ تُنشئ بايثون عادةً سلاسل تمثيل نصية للكائنات بطريقتين، سلسلة <em>repr</em> النصية وهي سلسلة نصية لشيفرة بايثون التي تُنشئ نسخة من الكائن عندما تُنفذ، وسلسلة <em>str</em> النصية التي هي سلسلة يستطيع الإنسان قراءتها وتؤمن معلومات واضحة ومفيدة عن الكائن. تعاد سلاسل repr و str عن طريق الدوال المبنية مسبقًا <code>repr()‎</code> و <code>str()‎</code> على التوالي. مثلًا، أدخل التالي إلى الصدفة التفاعلية لرؤية السلسلتين النصيتين repr و str للكائن <code>datetime.date</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_199_8" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> datetime
</span><span class="lit">1</span><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> newyears </span><span class="pun">=</span><span class="pln"> datetime</span><span class="pun">.</span><span class="pln">date</span><span class="pun">(</span><span class="lit">2021</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">1</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> repr</span><span class="pun">(</span><span class="pln">newyears</span><span class="pun">)</span><span class="pln">
</span><span class="lit">2</span><span class="pln"> </span><span class="str">'datetime.date(2021, 1, 1)'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">newyears</span><span class="pun">)</span><span class="pln">
</span><span class="lit">3</span><span class="pln"> </span><span class="str">'2021-01-01'</span><span class="pln">
</span><span class="lit">4</span><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> newyears
datetime</span><span class="pun">.</span><span class="pln">date</span><span class="pun">(</span><span class="lit">2021</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">1</span><span class="pun">)</span></pre>

<p>
	في هذا المثال، سلسلة repr‏ -أي <code>datetime.date(2021, 1, 1)‎</code>- للكائن <code>datetime.date</code>(السطر 2) هي حرفيًا سلسلة نصية لشيفرة <a href="https://academy.hsoub.com/programming/python/%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-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1815/" rel="">بايثون</a> التي تُنشئ نسخةً من الكائن (السطر 1). تؤمن هذه النسخة تمثيلًا دقيقًا للكائن، ومن جهة أخرى، السلسلة النصية str‏ -أي <code>2021-01-01</code>- للكائن <code>datetime.date</code> (السطر 3) هي سلسلة نصية تمثل قيمة الكائن بطريقة سهلة القراءة للبشر. إذا أدخلنا ببساطة الكائن في الصدفة التفاعلية (السطر 4)، تظهِر السلسلة النصية repr. تظهر غالبًا السلسلة النصية str للمستخدمين وتُستخدم السلسلة النصية repr للكائن في السياق التقني مثل رسائل الخطأ والسجلات.
</p>

<p>
	تعلم بايثون كيفية إظهار الكائنات في أنواعها المبنية مسبقًا مثل الأعداد الصحيحة والسلاسل النصية، ولكنها لا تعلم كيفية إظهار الكائنات للأصناف التي أنشأناها نحن. إذا لم يعرف <code>repr()‎</code> كيفية إنشاء سلسلة نصية repr أو str لكائن، ستكون السلسلة النصية مغلفة بأقواس مثلثة وتحتوي عنوان الذاكرة واسم للكائن <code>'&lt;wizcoin.WizCoin object at 0x00000212B4148EE0&gt;'</code> لإنشاء هذا النوع من السلاسل النصية لكائن <code>WizCoin</code> أدخل التالي إلى الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_199_11" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> wizcoin
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">=</span><span class="pln"> wizcoin</span><span class="pun">.</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">purse</span><span class="pun">)</span><span class="pln"> 
</span><span class="str">'&lt;wizcoin.WizCoin object at 0x00000212B4148EE0&gt;'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> repr</span><span class="pun">(</span><span class="pln">purse</span><span class="pun">)</span><span class="pln"> 
</span><span class="str">'&lt;wizcoin.WizCoin object at 0x00000212B4148EE0&gt;'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse
</span><span class="pun">&lt;</span><span class="pln">wizcoin</span><span class="pun">.</span><span class="typ">WizCoin</span><span class="pln"> object at </span><span class="lit">0x00000212B4148EE0</span><span class="pun">&gt;</span></pre>

<p>
	لا تمتلك هذه السلاسل فائدة كبيرة وصعبة القراءة، لذا يمكننا إخبار بايثون ما نريد استخدامه عن طريق تطبيق التوابع السحرية <code>‎__repr__()‎</code> و <code>‎__str__()‎</code>؛ إذ يحدد التابع <code>‎__repr__()‎</code> أي سلسلة نصية يجب أن تُعيدها بايثون عندما يمرر الكائن إلى الدالة المبنية مسبقًا <code>repr()‎</code>؛ بينما يحدد التابع <code>‎__str__()‎</code> أي سلسلة نصية يجب أن تُعيدها بايثون عندما يمرر الكائن إلى الدالة المبنية مسبقًا <code>str()‎</code>. ضِف التالي إلى نهاية ملف wizcoin.py:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_199_13" style=""><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">
    </span><span class="kwd">def</span><span class="pln"> __repr__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
        </span><span class="str">"""Returns a string of an expression that re-creates this object."""</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> f</span><span class="str">'{self.__class__.__qualname__}({self.galleons}, {self.sickles}, {self.knuts})'</span><span class="pln">

    </span><span class="kwd">def</span><span class="pln"> __str__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
        </span><span class="str">"""Returns a human-readable string representation of this object."""</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> f</span><span class="str">'{self.galleons}g, {self.sickles}s, {self.knuts}k'</span></pre>

<p>
	عندما نمرر <code>purse</code> إلى <code>repr()‎</code> و <code>str()‎</code> يستدعي بايثون التوابع السحرية <code>‎__repr__()‎</code> و <code>‎__str__()‎</code>، أي نحن لا نستدعي التوابع السحرية في الشيفرة الخاصة بنا.
</p>

<p>
	لاحظ أن السلسة النصية f التي تضم الكائن في الأقواس تستدعي ضمنًا <code>str()‎</code> للحصول على السلسة النصية str. مثلًا أدخل التالي إلى الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_199_15" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> wizcoin
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">=</span><span class="pln"> wizcoin</span><span class="pun">.</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> repr</span><span class="pun">(</span><span class="pln">purse</span><span class="pun">)</span><span class="pln">  </span><span class="com"># Calls WizCoin's __repr__() behind the scenes.</span><span class="pln">
</span><span class="str">'WizCoin(2, 5, 10)'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">purse</span><span class="pun">)</span><span class="pln">  </span><span class="com"># Calls WizCoin's __str__() behind the scenes.</span><span class="pln">
</span><span class="str">'2g, 5s, 10k'</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">f</span><span class="str">'My purse contains {purse}.'</span><span class="pun">)</span><span class="pln">  </span><span class="com"># Calls WizCoin's __str__().</span><span class="pln">
</span><span class="typ">My</span><span class="pln"> purse contains </span><span class="lit">2g</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5s</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10k</span><span class="pun">.</span></pre>

<p>
	عندما نمرر الكائن <code>WizCoin</code> في <code>purse</code> إلى الدالتين <code>repr()‎</code> و <code>str()‎</code>، تستدعي بايثون في الخلفية التابعين <code>‎__repr__()‎</code> و <code>‎__str__()‎</code> الخاصين بالصنف <code>WizCoin</code>. برمجنا هذين التابعين ليعيدا سلاسلًا نصيةً مفيدةً وسهلة القراءة. إذا أدخلت نص السلسلة النصية repr‏ التالية <code>‎'WizCoin(2, 5, 10)'‎</code> إلى الصدفة التفاعلية ستُنشئ كائن <code>WizCoin</code> لديه نفس سمات الكائن في <code>purse</code>. السلسلة النصية str هي تمثيل أسهل للقراءة لقيمة الكائن <code>2g, 5s, 10k</code>. إذا استخدمت الكائن <code>WizCoin</code> في السلسلة النصية f، ستستخدم بايثون السلسلة النصية str الخاصة بالكائن.
</p>

<p>
	إذا كانت الكائنات <code>WizCoin</code> معقدة لدرجة أنه من المستحيل إنشاء نسخة منها باستدعاء <a href="https://academy.hsoub.com/programming/python/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D8%A3%D8%B5%D9%86%D8%A7%D9%81-%D9%88%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-r754/" rel="">دالة بانية Constructor Function</a> واحدة، نغلف السلسلة النصية repr في قوسين مثلثين للتنويه على أنه لا يمكن أن تصبح شيفرة بايثون. هكذا تكون سلسلة تمثيل نصي العامة، مثل <code>'&lt;wizcoin.WizCoin object at 0x00000212B4148EE0&gt;'</code>. كتابة ذلك في الصَدَفة التفاعلية سيرفع خطأ <code>SyntaxError</code> حتى لا يحدث ارتباك بشيفرة بايثون التي تُنشئ نسخة من ذلك الكائن.
</p>

<p>
	نستخدم <code>__self.__class__.__qualname</code> بدلًا من توفير السلسلة النصية <code>WizCoin</code> في الشيفرة داخل التابع <code>‎__repr__()‎</code>، إذ يستخدم التابع الموروث <code>‎__repr__()‎</code> اسم الصنف الفرعي بدلًا من <code>WizCoin</code>. إذا أعدنا تسمية الصنف <code>WizCoin</code> سيستخدم التابع <code>‎__repr__()‎</code> الاسم الجديد تلقائيًا. تظهِر السلسلة النصية str للكائن <code>WizCoin</code> السمة بصورة أنيقة ومختصرة. يُفضّل جدًا تطبيق <code>‎__repr__()‎</code> و <code>‎__str__()‎</code> في كل الأصناف الخاصة بك.
</p>

<h2 id="repr">
	المعلومات الحساسة في سلاسل REPR النصية
</h2>

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

<h2 id="numericdundermethods">
	التوابع السحرية العددية Numeric Dunder Methods
</h2>

<p>
	تزيد التوابع السحرية العددية أو التوابع السحرية الرياضية من تحميل عامل بايثون الرياضية، مثل <code>+</code> و <code>-</code> و <code>*</code> و <code>/</code> وما شابه. لا نستطيع حاليًا تنفيذ عملية رياضية مثل جمع كائني <code>WizCoin</code> باستخدام العامل <code>+</code>، وإذا حاولنا فعل ذلك سترفع بايثون استثناء <code>TypeError</code> لأنها لا تعرف كيفية إضافة كائنات <code>WizCoin</code>. أدخل التالي إلى الصدفة التفاعلية لمشاهدة هذا الخطأ:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_199_17" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> wizcoin
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">=</span><span class="pln"> wizcoin</span><span class="pun">.</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> tipJar </span><span class="pun">=</span><span class="pln"> wizcoin</span><span class="pun">.</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">37</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">+</span><span class="pln"> tipJar
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;stdin&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">TypeError</span><span class="pun">:</span><span class="pln"> unsupported operand type</span><span class="pun">(</span><span class="pln">s</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"> </span><span class="str">'WizCoin'</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="str">'WizCoin'</span></pre>

<p>
	يمكنك استخدام التابع السحري <code>‏()‏‏__add__‏</code> بدلًا من كتابة التابع <code>‎addWizCoin()‎‎‏‏‏‎</code> لصنف <code>WizCoin</code>، لكي تعمل كائنات <code>WizCoin</code> مع العامل <code>+</code>. أضف التالي إلى نهاية ملف wizcoin.py:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_199_19" style=""><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">
</span><span class="lit">1</span><span class="pln">     </span><span class="kwd">def</span><span class="pln"> __add__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">):</span><span class="pln">
        </span><span class="str">"""Adds the coin amounts in two WizCoin objects together."""</span><span class="pln">
</span><span class="lit">2</span><span class="pln">         </span><span class="kwd">if</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> isinstance</span><span class="pun">(</span><span class="pln">other</span><span class="pun">,</span><span class="pln"> </span><span class="typ">WizCoin</span><span class="pun">):</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">NotImplemented</span><span class="pln">

</span><span class="lit">3</span><span class="pln">         </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">WizCoin</span><span class="pun">(</span><span class="pln">other</span><span class="pun">.</span><span class="pln">galleons </span><span class="pun">+</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">galleons</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">.</span><span class="pln">sickles </span><span class="pun">+</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">sickles</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">.</span><span class="pln">knuts </span><span class="pun">+</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">knuts</span><span class="pun">)</span></pre>

<p>
	تستدعي بايثون التابع <code>()__add__</code>عندما يكون الكائن <code>WizCoin</code> على يسار المعامل <code>+</code> وتمرر القيمة على الجانب الأيمن من المعامل <code>+</code> للمعامل <code>other</code> (يمكن تسمية المعامل أي شيء ولكن الاصطلاح هو <code>other</code>).
</p>

<p>
	تذكر أنه يمكن تمرير أي نوع من <a href="https://academy.hsoub.com/programming/python/%D9%81%D9%87%D9%85-%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-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-r720/" rel="">أنواع </a> الكائنات إلى التابع <code>()__add__</code>، لذا يجب على التابع أن يحتوي اختبارات من النوع، فمثلًا ليس من المنطقي إضافة <a href="https://wiki.hsoub.com/Python/float" rel="external">رقم عشري</a> أو <a href="https://wiki.hsoub.com/Python/int" rel="external">عدد صحيح</a> إلى كائن <code>WizCoin</code> لأننا لا نعرف إذا كان يجب إضافته إلى <code>galleons</code> أو <code>sickles</code> أو <code>knuts</code>.
</p>

<p>
	يُنشئ التابع <code>()__add__</code> كائن <code>WizCoin</code> جديد مع كميات تساوي مجموع السمات <code>galleons</code> و <code>sickles</code> و <code>knuts</code> من <code>self</code> و <code>other</code>3 لأن هذه السمات الثلاث تحتوي الأعداد الصحيحة التي يمكننا استخدام المعامل <code>+</code> عليهم. الآن بعد أن حمّلنا العامل <code>+</code> لصنف <code>WizCoin</code>، يمكننا استخدام العامل <code>+</code> على الكائن <code>WizCoin</code>.
</p>

<p>
	يسمح لنا زيادة تحميل العامل <code>+</code> بكتابة شيفرة أكثر قابليّة للقراءة. مثلًا، أدخل التالي إلى الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_199_21" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> wizcoin
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">=</span><span class="pln"> wizcoin</span><span class="pun">.</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln">  </span><span class="com"># إنشاء كائن‫ WizCoin</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> tipJar </span><span class="pun">=</span><span class="pln"> wizcoin</span><span class="pun">.</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">37</span><span class="pun">)</span><span class="pln">  </span><span class="com"># إنشاء كائن‫ WizCoin آخر</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">+</span><span class="pln"> tipJar  </span><span class="com"># إنشاء كائن‫ WizCoin آخر يحتوي على المجموع</span><span class="pln">
</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">47</span><span class="pun">)</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_199_23" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> wizcoin
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">=</span><span class="pln"> wizcoin</span><span class="pun">.</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">+</span><span class="pln"> </span><span class="lit">42</span><span class="pln">  </span><span class="com"># لا يمكن إضافة كائنات‫ WizCoin مع الأعداد الصحيحة</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;stdin&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">TypeError</span><span class="pun">:</span><span class="pln"> unsupported operand type</span><span class="pun">(</span><span class="pln">s</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"> </span><span class="str">'WizCoin'</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="str">'int'</span></pre>

<p>
	تشير إعادة <code>NotImplemented</code> إلى بايثون لاستدعاء التوابع لتؤدي هذه العملية. سنتوسع حول "التوابع السحرية العددية المعكوسة" بتفصيل أكثر في هذا المقال. تستدعي بايثون في الخلفية التابع <code>()__add__</code> مع <code>42</code> للمعامل <code>other</code> الذي يعيد <code>NotImplemented</code> مما يؤدي لأن ترفع بايثون <code>TypeError</code>.
</p>

<p>
	على الرغم من أنه لا يجب إضافة الأعداد الصحيحة أو طرحهم من الكائن <code>WizCoin</code> إلا أنه من المنطقي السماح للشيفرة بضرب كائنات <code>WizCoin</code> بأعداد صحيحة موجبة عن طريق تعريف تابع سحري <code>()__mul__</code>. ضِف التالي في نهاية الملف wizcoin.py:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_199_25" style=""><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">
    </span><span class="kwd">def</span><span class="pln"> __mul__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">):</span><span class="pln">
        </span><span class="str">"""Multiplies the coin amounts by a non-negative integer."""</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> isinstance</span><span class="pun">(</span><span class="pln">other</span><span class="pun">,</span><span class="pln"> int</span><span class="pun">):</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">NotImplemented</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> other </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="com"># Multiplying by a negative int results in negative</span><span class="pln">
            </span><span class="com"># amounts of coins, which is invalid.</span><span class="pln">
            </span><span class="kwd">raise</span><span class="pln"> </span><span class="typ">WizCoinException</span><span class="pun">(</span><span class="str">'cannot multiply with negative integers'</span><span class="pun">)</span><span class="pln">

        </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">WizCoin</span><span class="pun">(</span><span class="pln">self</span><span class="pun">.</span><span class="pln">galleons </span><span class="pun">*</span><span class="pln"> other</span><span class="pun">,</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">sickles </span><span class="pun">*</span><span class="pln"> other</span><span class="pun">,</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">knuts </span><span class="pun">*</span><span class="pln"> other</span><span class="pun">)</span></pre>

<p>
	يسمح لك التابع <code>()__mul__</code> بضرب كائنات <code>WizCoin</code> بأعداد صحيحة موجبة. إذا كان <code>other</code> عدد صحيح، فهذا يعني أنه نوع البيانات التي يتوقعه التابع <code>()__mul__</code> ولا يجب أن نعيد <code>NotImplemented</code>. ولكن إذا كان العدد الصحيح سالبًا، هذا يعني أن ضربه الكائن <code>WizCoin</code> سيعطي قيم سلبية للنقود في الكائن <code>WizCoin</code> لأن هذا يتعارض مع تصميمنا للصنف، نرفع <code>WizCoinException</code> مع رسالة خطأ مفصلة.
</p>

<p>
	ملاحظة: لا يجب تغيير الكائن <code>self</code> في التابع السحري العددي، بل يجب على التابع إنشاء وإعادة كائن جديد بدلًا من ذلك، إذ يُتوقع من العامل <code>+</code> ومن باقي العوامل أيضًا تقييم كائن جديد بدلًا من تعديل قيمة الكائن الموضعي.
</p>

<p>
	أدخل التالي في الصدفة التفاعلية لمشاهدة عمل التابع السحري <code>()__mul__</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_199_27" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> wizcoin
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">=</span><span class="pln"> wizcoin</span><span class="pun">.</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln">  </span><span class="com"># إنشاء كائن‫ WizCoin</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">*</span><span class="pln"> </span><span class="lit">10</span><span class="pln">  </span><span class="com"># ‫اضرب كائن WizCoin بعدد صحيح</span><span class="pln">
</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">20</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</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">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">*</span><span class="pln"> </span><span class="pun">-</span><span class="lit">2</span><span class="pln">  </span><span class="com"># الضرب بعدد صحيح سالب يتسبب بخطأ</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;stdin&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"C:\Users\Al\Desktop\wizcoin.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">86</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> __mul__
    </span><span class="kwd">raise</span><span class="pln"> </span><span class="typ">WizCoinException</span><span class="pun">(</span><span class="str">'cannot multiply with negative integers'</span><span class="pun">)</span><span class="pln">
wizcoin</span><span class="pun">.</span><span class="typ">WizCoinException</span><span class="pun">:</span><span class="pln"> cannot multiply </span><span class="kwd">with</span><span class="pln"> negative integers</span></pre>

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

<table>
	<thead>
		<tr>
			<th>
				التابع السحري
			</th>
			<th>
				العملية
			</th>
			<th>
				المعامل أو الدالة المضمنة
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				<code>()__add__</code>
			</td>
			<td>
				جمع
			</td>
			<td>
				<code>+</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__sub__</code>
			</td>
			<td>
				طرح
			</td>
			<td>
				<code>-</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__mul__</code>
			</td>
			<td>
				ضرب
			</td>
			<td>
				<code>*</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__matmul__</code>
			</td>
			<td>
				ضرب المصفوفات (جديد في بايثون 3.5)
			</td>
			<td>
				<code>@</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__truediv__</code>
			</td>
			<td>
				قسمة
			</td>
			<td>
				<code>/</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__floordiv__</code>
			</td>
			<td>
				قسمة عدد صحيح
			</td>
			<td>
				<code>//</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__mod__</code>
			</td>
			<td>
				نسبة
			</td>
			<td>
				<code>%</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__divmod__</code>
			</td>
			<td>
				قسمة ونسبة
			</td>
			<td>
				<code>divmode()‎</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__pow__</code>
			</td>
			<td>
				رفع للأس
			</td>
			<td>
				<code>**</code>, <code>pow</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__lshift__</code>
			</td>
			<td>
				انتقال لليسار
			</td>
			<td>
				<code>&gt;&gt;</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__rshift__</code>
			</td>
			<td>
				انتقال لليمين
			</td>
			<td>
				<code>&lt;&lt;</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__and__</code>
			</td>
			<td>
				عملية ثنائية و
			</td>
			<td>
				<code>&amp;</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__or__</code>
			</td>
			<td>
				عملية ثنائية أو
			</td>
			<td>
				<code>|</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__xor__</code>
			</td>
			<td>
				عملية ثنائية أو حصرية
			</td>
			<td>
				<code>^</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__neg__</code>
			</td>
			<td>
				سلبي
			</td>
			<td>
				أحادي <code>-</code> كما في <code>-42</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__pos__</code>
			</td>
			<td>
				هوية
			</td>
			<td>
				أحادي <code>+</code> كما في <code>+42</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__abs__</code>
			</td>
			<td>
				قيمة مطلقة
			</td>
			<td>
				<code>()abs</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__invert__</code>
			</td>
			<td>
				عملية ثنائية عكس
			</td>
			<td>
				<code>~</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__complex__</code>
			</td>
			<td>
				شكل العدد العقدي
			</td>
			<td>
				<code>complex()‎</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__int__</code>
			</td>
			<td>
				شكل العدد الصحيح
			</td>
			<td>
				<code>int()‎</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__float__</code>
			</td>
			<td>
				شكل العدد العشري
			</td>
			<td>
				<code>float()‎</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__bool__</code>
			</td>
			<td>
				شكل بولياني
			</td>
			<td>
				<code>bool()‎</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__round__</code>
			</td>
			<td>
				التدوير
			</td>
			<td>
				<code>round()‎</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__trunc__</code>
			</td>
			<td>
				الاختصار
			</td>
			<td>
				<code>math.trunc()‎</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__floor__</code>
			</td>
			<td>
				التدوير للأسفل
			</td>
			<td>
				<code>math.floor()‎</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__ceil__</code>
			</td>
			<td>
				التدوير للأعلى
			</td>
			<td>
				<code>math.ceil()‎</code>
			</td>
		</tr>
	</tbody>
</table>

<p style="text-align: center;">
	الجدول 1: التوابع السحرية العددية
</p>

<p>
	بعض هذه التوابع مهمة لصنف <code>WizCoin</code>، حاول كتابة التطبيق الخاص بك لكل من التوابع <code>()__sub__</code> و <code>()__pow__</code> و <code>()__int__</code> و <code>()__float__</code> و <code>()__bool__</code>. يمكنك مشاهدة أمثلة عن التطبيقات من خلال الرابط <a href="https://autbor.com/wizcoinfull" rel="external nofollow"> https://autbor.com/wizcoinfull</a>. التوثيق الكامل للتوابع السحرية العددية موجود في توثيقات بايثون على الرابط <a href="https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types" rel="external nofollow">https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types</a>.
</p>

<p>
	تسمح التوابع السحرية العددية للكائنات الخاصة بأصنافك استخدام العوامل الرياضية الخاصة ببايثون. استخدم التوابع السحرية العددية في حال كتبت توابع تصف مهمة تابع موجود سابقًا أو دالة مبنية مسبقًا، مثل التابعين <code>multiplyBy()‎</code> أو <code>convertToInt()‎</code> أو ما شابه، إضافةً إلى التوابع السحرية المعكوسة أو الموضعية المشروحة في الفقرتين التاليتين.
</p>

<h2 id="-1">
	التوابع السحرية العددية المعكوسة
</h2>

<p>
	تستدعي بايثون التوابع السحرية العددية عندما يكون الكائن على يسار العامل الرياضي، ولكنها تستدعي التابع السحري العددي المعكوس (يسمى أيضًا التابع السحري العددي العكوس أو اليد اليمين) عندما يكون الكائن على الطرف اليمين من العامل الرياضي.
</p>

<p>
	التوابع السحرية العددية المعكوسة مفيدة لأن المبرمجين الذين يستخدمون الأصناف الخاصة بك لا يكتبون دومًا الكائن على الطرف اليسار من العامل الذي يقود بدوره لسلوك غير متوقع. لنرى مثلًا ما سيحدث عندما تحتوي <code>purse</code> كائن <code>WizCoin</code> وتعطي بايثون القيمة للتعبير <code>2 * purse</code> حيث <code>purse</code> هي على الطرف اليمين للمعامل.
</p>

<ol>
	<li>
		يُستدعى التابع <code>()__mul__</code> للصنف <code>int</code> لأن <code>2</code> هو عدد صحيح، وذلك مع تمرير <code>purse</code> للمعامل <code>other</code>.
	</li>
	<li>
		لا يعرف التابع <code>()__mul__</code> للصنف <code>int</code> كيف يتعامل مع الكائنات <code>WizCoin</code> لذا يُعيد <code>NotImplemented</code>.
	</li>
	<li>
		لا ترفع بايثون الخطأ <code>TypeError</code> الآن لأن <code>purse</code> تحتوي كائن <code>WizCoin</code>، ويُستدعى التابع <code>()__rmul__</code> الخاص بالصنف <code>WizCoin</code> باستخدام <code>2</code> ويُمرر إلى المعامل <code>other</code>.
	</li>
	<li>
		ترفع بايثون الخطأ <code>TypeError</code> إذا أعاد التابع <code>‎__‎rmul__‎()‎</code>‏ القيمة <code>NotImplemented</code>.
	</li>
</ol>

<p>
	ما عدا ذلك تكون القيمة المعادة من <code>()__rmul__</code> هي نتيجة التعبير <code>2 * purse</code>.
</p>

<p>
	يعمل التعبير<code>purse * 2</code> بصورة مختلفة عندما تكون <code>purse</code> على الجانب الأيسر من المعامل:
</p>

<ol>
	<li>
		لأن <code>purse</code> تحتوي كائن <code>WizCoin</code>، إذ يُستدعى تابع <code>()__mul__</code> الخاص بالصنف <code>WizCoin</code> ويمرر <code>2</code> للمعامل <code>other</code>.
	</li>
	<li>
		ينشئ التابع <code>()__mul__</code> كائن <code>WizCoin</code> جديد ويعيده.
	</li>
	<li>
		الكائن المُعاد هو قيمة التعبير <code>purse * 2</code>.
	</li>
</ol>

<p>
	لدى التوابع السحرية العددية والتوابع السحرية العددية المعكوسة نفس الشيفرة إذا كانت متبادلة. العوامل المتبادلة مثل الجمع لديها نفس النتيجة بالاتجاهين، <code>3+2</code> هي نفس <code>2+3</code>، ولكن المعاملات الأخرى ليست تبادلية فمثلًا <code>3-2</code> ليست <code>2-3</code>. أي عملية تبادلية يمكنها استدعاء نفس التابع السحري العددي الأساسي عندما يُستدعى التابع السحري العددي المعكوس؛ فمثلًا، أضف التالي في نهاية ملف wizcoin.py لتعريف التابع السحري العددي المعكوس لعامل الضرب:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_199_29" style=""><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">
    </span><span class="kwd">def</span><span class="pln"> __rmul__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">):</span><span class="pln">
        </span><span class="str">"""Multiplies the coin amounts by a non-negative integer."""</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">__mul__</span><span class="pun">(</span><span class="pln">other</span><span class="pun">)</span></pre>

<p>
	ضرب عدد صحيح بكائن <code>WizCoin</code> هو تبادلي، إذ أن <code>2 * purse</code> هي نفس <code>purse * 2</code>. بدلًا من نسخ ولصق الشيفرة من <code>()__mul__</code> نستدعي فقط <code>self.__mul__()‎</code> ونمررها للمعامل <code>other</code>.
</p>

<p>
	بعد تحديث <em>mizcoin.py</em>، جرب استخدام تابع الضرب السحري المعكوس عن طريق إدخال التالي إلى الصدفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_199_31" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> wizcoin
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">=</span><span class="pln"> wizcoin</span><span class="pun">.</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">*</span><span class="pln"> </span><span class="lit">10</span><span class="pln">  </span><span class="com"># ‪‫يستدعي ‎__mul__()‎ بقيمة 10 للمعامل other</span><span class="pln">
</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">20</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</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">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> purse  </span><span class="com">#  ‪‫يستدعي ‎__rmul__()‎ بقيمة 10 للمعامل other</span><span class="pln">
</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">20</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">)</span></pre>

<p>
	تذكر أن بايثون تستدعي في التعبير <code>10 * purse</code> تابع <code>‏‏()__mul__‏‏</code> الخاص بالصنف <code>int</code> لمعرفة ما إذا كان بإمكان العدد الصحيح أن يُضرب بكائنات <code>WizCoin</code>. لا يعلم طبعًا صنف بايثون <code>int</code> المبني مسبقًا أي شيء عن الأصناف التي أنشأناها، لذا تعيد <code>NotImplemented</code>. هذا يشير لبايثون باستدعاء التابع <code>()__rmul__</code> الخاص بصنف <code>WizCoin</code>، وإذا كان موجودًا للتعامل مع العملية الحسابية،ترفع بايثون استثناء <code>TypeError</code> إذا كان الاستدعائين للتابعين <code>()__mul__</code> و <code>()__rmul__</code> للصنفين <code>Int</code> و <code>WizCoin</code> على التتالي يعيدان <code>NotImplemented</code>.
</p>

<p>
	يمكن إضافة كائنات <code>WizCoin</code> إلى بعضها فقط، وهذا يضمن أن التابع الأول <code>()__add__</code> الخاص بالصنف <code>WizCoin</code> سيتعامل مع المعامل لذا لا نحتاج لتنفيذ <code>()__radd__</code>. مثلًا، في التعبير <code>purse + tipJar</code> يُستدعى التابع <code>()__add__</code> للكائن <code>purse</code> وتمرّر <code>tipJar</code> للمعامل <code>other</code>. لا تحاول بايثون استدعاء تابع <code>()__radd__</code> الخاص بالكائن <code>tipJar</code> لأن هذا الاستدعاء لن يعيد <code>NotImplemented</code>، وتكون <code>purse</code> هي المعامل <code>other</code>.
</p>

<p>
	يحتوي الجدول 2 على قائمة كاملة للتوابع السحرية العددية المعكوسة.
</p>

<table>
	<thead>
		<tr>
			<th>
				التابع السحري
			</th>
			<th>
				العملية
			</th>
			<th>
				المعامل أو الدالة المضمنة
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				<code>()__radd__</code>
			</td>
			<td>
				جمع
			</td>
			<td>
				<code>+</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__rsub__</code>
			</td>
			<td>
				طرح
			</td>
			<td>
				<code>-</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__rmul__</code>
			</td>
			<td>
				ضرب
			</td>
			<td>
				<code>*</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__rmatmul__</code>
			</td>
			<td>
				ضرب المصفوفات (جديد في بايثون 3.5)
			</td>
			<td>
				<code>@</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__rtruediv__</code>
			</td>
			<td>
				قسمة
			</td>
			<td>
				<code>/</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__rfloordiv__</code>
			</td>
			<td>
				قسمة عدد صحيح
			</td>
			<td>
				<code>//</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__rmod__</code>
			</td>
			<td>
				نسبة
			</td>
			<td>
				<code>%</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__rdivmod__</code>
			</td>
			<td>
				قسمة ونسبة
			</td>
			<td>
				<code>divmode()‎</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__rpow__</code>
			</td>
			<td>
				رفع للأس
			</td>
			<td>
				<code>pow</code>, <code>**</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__rlshift__</code>
			</td>
			<td>
				انتقال لليسار
			</td>
			<td>
				<code>&lt;&lt;</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__rrshift__</code>
			</td>
			<td>
				انتقال لليمين
			</td>
			<td>
				<code>&gt;&gt;</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__rand__</code>
			</td>
			<td>
				عملية ثنائية و
			</td>
			<td>
				<code>&amp;</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__ror__</code>
			</td>
			<td>
				عملية ثنائية أو
			</td>
			<td>
				<code>|</code>
			</td>
		</tr>
		<tr>
			<td>
				<code>()__rxor__</code>
			</td>
			<td>
				عملية ثنائية أو حصرية
			</td>
			<td>
				<code>^</code>
			</td>
		</tr>
	</tbody>
</table>

<p style="text-align: center;">
	الجدول 2: التوابع السحرية العددية المعكوسة
</p>

<p>
	<a href="https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types" rel="external nofollow">التوثيق الكامل للتوابع السحرية المعكوسة موجود في توثيقات بايثون</a>.
</p>

<h2 id="-2">
	الخلاصة
</h2>

<p>
	تسمح لك بايثون بإعادة تعريف العوامل باستخدام التوابع السحرية التي تبدأ وتنتهي بمحرفي شرطة سفلية، كما يمكن إعادة صياغة العوامل الرياضية الشائعة باستخدام التوابع السحرية العددية والمعكوسة، إذ تقدم هذه التوابع طريقة لعمل عوامل بايثون الموضعية مع كائنات الأصناف التي أنشأتها وإذا لم تكن قادرة على التعامل مع نوع بيانات الكائن على الطرف الأخر من المعامل ستعيد قيمة <code>NotImplemented</code> المبنية مسبقًا. تُنشئ هذه التوابع السحرية وتعيد كائنات جديدة، في حين تُعدل التوابع السحرية الموضعية (التي تُعيد تعريف معاملات الإسناد المدعومة) الكائنات موضعيًا. لا تنفذ التوابع السحرية المقارنة معاملات بايثون الستة للمقارنة فقط، ولكن تسمح لدالة بايثون <code>sort()‎</code> بترتيب كائنات الأصناف الخاصة بك. ستحتاج لاستخدام الدوال <code>eq()‎</code> و <code>ne()‎</code> و <code>lt()‎</code> و <code>le()‎</code> و <code>gt()‎</code> و <code>ge()‎</code> في وحدة العامل لمساعدتك في تنفيذ هذه التوابع السحرية.
</p>

<p>
	تسمح الخواص والتوابع السحرية بكتابة الأصناف الخاصة بك بطريقة متناسقة وقابلة للقراءة، كما تسمح لك بتفادي الشيفرة النمطية التي تتطلبها لغات البرمجة الأخرى مثل <a href="https://academy.hsoub.com/programming/java/" rel="">جافا</a>. لتعلم كتابة شيفرة بايثون هناك حديثان لريموند هيتغير Raymond Hettiger يتوسعان في هذه الأفكار "<a href="https://youtu.be/OSGv2VnC0go/" rel="external nofollow">تحويل الشيفرة إلى بايثون اصطلاحية</a>". و"<a href="https://youtu.be/wf-BqAjZb8M/" rel="external nofollow">ما وراء PEP 8 - أفضل الممارسات لشيفرة جميلة وواضحة</a>" التي تغطي بعض المفاهيم التي ذكرناها وأكثر.
</p>

<p>
	ترجمة -وبتصرف- لقسم من الفصل <a href="http://inventwithpython.com/beyond/chapter17.html" rel="external nofollow">Pythonic <abbr title="Object-Oriented Programming | البرمجة كائنية التوجه"><abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr></abbr>: Properities and dunder methods</a> من كتاب <a href="https://inventwithpython.com/beyond//" rel="external nofollow">Beyond the Basic Stuff with Python</a>.
</p>

<h2 id="-3">
	اقرأ المزيد
</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-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-properties-r2188/" rel="">البرمجة كائنية التوجه في بايثون: الخاصيات Properties</a>.
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%B1%D9%8A%D8%A7%D8%B6%D9%8A%D8%A9-%D8%A7%D9%84%D9%85%D8%B6%D9%85%D9%86%D8%A9-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-r731/" rel="">الدوال الرياضية المضمنة في بايثون 3</a>.
	</li>
	<li>
		<a href="https://wiki.hsoub.com/Python#.D8.A7.D9.84.D8.A3.D8.AE.D8.B7.D8.A7.D8.A1_.D9.88.D8.A7.D9.84.D8.A7.D8.B3.D8.AA.D8.AB.D9.86.D8.A7.D8.A1.D8.A7.D8.AA" rel="external">توثيق بايثون</a>.
	</li>
</ul>
]]></description><guid isPermaLink="false">2192</guid><pubDate>Sat, 09 Dec 2023 16:05: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; &#x641;&#x64A; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646;: &#x627;&#x644;&#x62E;&#x627;&#x635;&#x64A;&#x627;&#x62A; Properties</title><link>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-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-properties-r2188/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_12/-------Properties.png.c4e17ac352a724bdbc0ea596045ebd9a.png" /></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> ميزات <a href="https://academy.hsoub.com/programming/python/%D9%85%D8%AE%D8%AA%D8%B5%D8%B1-%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-%D9%88%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D9%87%D8%A7-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1926/" rel="">البرمجة كائنية التوجه</a> ولكن تمتلك <a href="https://academy.hsoub.com/python/" rel="">لغة بايثون Python</a> أفضلها. سيساعدك تعلم كيفية استخدام هذه التقنيات الخاصة ببايثون على كتابة شيفرة مختصرة وسهلة القراءة.
</p>

<p>
	تسمح الخاصيات بتنفيذ شيفرة معينة في كل مرة تُقرأ أو تُعدل أو تُحذف سمة كائن معين لضمان عدم وضع الكائن في حالة غير صالحة. تسمى هذه التوابع في لغات البرمجة الأخرى بالجالبة getters أو الضابطة setters. تسمح لك <a href="https://academy.hsoub.com/programming/python/%D9%85%D8%B5%D8%B7%D9%84%D8%AD%D8%A7%D8%AA-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1982/" rel="">التوابع السحرية Dunder methods</a> باستخدام الكائن الخاص بك مع عوامل بايثون، مثل عامل <code>+</code> ويسمح لك ذلك بجمع كائني <code>datetime.timedelta</code> مثل <code>datetime.timedelta(days=2)‎‏‏‏‏‏‏</code> و <code>datetime.timedelta(days=3)‎‏</code> لإنشاء كائن <code>datetime.timedelta(days=5)‎</code>.
</p>

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

<h2 id="properties">
	الخاصيات Properties
</h2>

<p>
	وسَمَ الصنف <code>BankAccount</code> المستخدم سابقًا السمة <code>‏‏balance_</code> بأنها خاصة private عن طريق وضع شرطة سفلية في بداية الاسم، ولكن تذكر أن وصف سمة أنها خاصة هو اصطلاح. كل السمات في <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>balance_</code> سواءً عن قصد أو بغير قصد إلى قيمة غير صالحة.
</p>

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

<h2 id="">
	تحويل السمة إلى خاصية
</h2>

<p>
	لننشئ أولًا صنفًا بسيطًا لديه سمة عادية بدلًا من خاصية. افتح نافذة محرر ملفات جديدة وأدخِل الشيفرة التالية واحفظه على النحو التالي regularAttributeExample.py:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7527_6" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">ClassWithRegularAttributes</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"> someParameter</span><span class="pun">):</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">someAttribute </span><span class="pun">=</span><span class="pln"> someParameter

obj </span><span class="pun">=</span><span class="pln"> </span><span class="typ">ClassWithRegularAttributes</span><span class="pun">(</span><span class="str">'some initial value'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">.</span><span class="pln">someAttribute</span><span class="pun">)</span><span class="pln">  </span><span class="com"># ‫يطبع‏ 'some initial value'</span><span class="pln">
obj</span><span class="pun">.</span><span class="pln">someAttribute </span><span class="pun">=</span><span class="pln"> </span><span class="str">'changed value'</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">.</span><span class="pln">someAttribute</span><span class="pun">)</span><span class="pln">  </span><span class="com"># يطبع‫ 'changed value'</span><span class="pln">
</span><span class="kwd">del</span><span class="pln"> obj</span><span class="pun">.</span><span class="pln">someAttribute  </span><span class="com"># يحذف السمة‫ someAttribute</span></pre>

<p>
	يحتوي الصنف <code>ClassWithRegularAttributes</code> على سمة عادية اسمها <code>someAttribute</code>. يضبط التابع <a href="https://wiki.hsoub.com/Python/class_definition#.D8.A7.D9.84.D8.AA.D8.A7.D8.A8.D8.B9_init_.28.29" rel="external"><code>‎__init__()‎</code></a> السمة <code>someAttribute</code> إلى <code>some initial value</code>، ومن ثم مباشرة نغير قيمة السمة إلى <code>changed value</code>، وعند تنفيذ البرنامَج ستكون المُخرجات على النحو التالي:
</p>

<pre class="ipsCode" id="ips_uid_7527_12">some initial value
changed value</pre>

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

<p>
	لنعيد كتابة هذا الصنف باستخدام الخواص، وذلك عن طريق تطبيق الخطوات التالية على سمة تُدعى <code>someAttribute</code>:
</p>

<ol>
	<li>
		أعِد تسمية السمة مع بادئة هي شرطة سفلية <code>‎_someAttribute</code>
	</li>
	<li>
		أنشئ تابعًا اسمه <code>someAttribue</code> مع <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B2%D8%AE%D8%B1%D9%81%D8%A7%D8%AA-decorators-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r303/" rel="">المزخرف</a> <code>@property</code>. لدى هذا التابع الجالب المعامل <code>self</code> الموجود لدى كل التوابع.
	</li>
	<li>
		أنشئ تابع آخر اسمه <code>someAttribute</code> مع المزخرف <code>someAttribute.setter@</code>. لدى هذا التابع الضابط المعاملين <code>self</code> و <code>value</code>.
	</li>
	<li>
		أنشئ تابع آخر اسمه <code>someAttribute</code> مع المزخرف <code>someAttribute.deleter@</code>. لدى هذا التابع الحاذف المعامل <code>self</code> الموجود لدى كل التوابع.
	</li>
</ol>

<p>
	افتح نافذة محرر ملفات جديدة وادخل الشيفرة التالية واحفظها على النحو التالي propertiesExample.py<em>‎</em>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7527_10" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">ClassWithProperties</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">
        self</span><span class="pun">.</span><span class="pln">someAttribute </span><span class="pun">=</span><span class="pln"> </span><span class="str">'some initial value'</span><span class="pln">

    </span><span class="lit">@property</span><span class="pln">
    </span><span class="kwd">def</span><span class="pln"> someAttribute</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">
        </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">_someAttribute

    </span><span class="lit">@someAttribute</span><span class="pun">.</span><span class="pln">setter
    </span><span class="kwd">def</span><span class="pln"> someAttribute</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> value</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">_someAttribute </span><span class="pun">=</span><span class="pln"> value

    </span><span class="lit">@someAttribute</span><span class="pun">.</span><span class="pln">deleter
    </span><span class="kwd">def</span><span class="pln"> someAttribute</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">
        </span><span class="kwd">del</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">_someAttribute

obj </span><span class="pun">=</span><span class="pln"> </span><span class="typ">ClassWithProperties</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">.</span><span class="pln">someAttribute</span><span class="pun">)</span><span class="pln"> </span><span class="com"># ‫يطبع 'some initial value'</span><span class="pln">
obj</span><span class="pun">.</span><span class="pln">someAttribute </span><span class="pun">=</span><span class="pln"> </span><span class="str">'changed value'</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">.</span><span class="pln">someAttribute</span><span class="pun">)</span><span class="pln"> </span><span class="com"># يطبع‫ 'changed value'</span><span class="pln">
</span><span class="kwd">del</span><span class="pln"> obj</span><span class="pun">.</span><span class="pln">someAttribute </span><span class="com"># يحذف السمة‫ _someAttribute</span></pre>

<p>
	خرج هذا البرنامج هو خرج الشيفرة في regularAttributeExample.py<em>‎</em> ذاتها لأنهما ينفذان المهمة ذاتها وهي طباعة السمة الأولية للكائن ومن ثم تحديث السمة وطباعتها مجددًا.
</p>

<p>
	لاحظ أن الشيفرة خارج الصنف لا تصل مباشرةً إلى السمة <code>someAttribute_</code> (لأنها خاصة)، ولكنها تصل إلى خاصية <code>someAttribute</code>. مكونات هذه الخاصية هي مجردة نوعًا ما، وهي التوابع الجالبة والضابطة والحاذفة. عندما نعيد تسمية سمة اسمها <code>someAttribute</code> إلى <code>‎_someAttribute</code> أثناء إنشاء توابع جالية وضابطة وحاذفة نسمي ذلك خاصية <code>someAttribute</code>.
</p>

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

<ul>
	<li>
		عندما تنفذ بايثون شيفرة تصل إلى تابع مثل <code>print(obj.someAttribute)‎</code>، فإنها تستدعي في الخلفية تابع الجلب وتستخدم القيمة المعادة.
	</li>
	<li>
		عندما تنفذ بايثون تعليمة إسناد مع خاصية، مثل <code>'obj.someAttribute = 'changed value</code>، فإنها تستدعي في الخلفية تابع الضبط وتمرر السلسلة النصية <code>'changed value'</code> من أجل المعامل <code>value</code>.
	</li>
	<li>
		عندما تنفذ بايثون تعليمة <code>del</code> مع خاصية مثل <code>del obj.someAttribute</code>، تستدعي في الخلفية تابع الحذف.
	</li>
</ul>

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

<p>
	افتح <a href="https://academy.hsoub.com/programming/workflow/%D9%85%D8%AD%D8%B1%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%B9%D9%85%D9%84%D8%A9-%D9%81%D9%8A-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r1438/" rel="">محرر النصوص</a> وادخل الشيفرة التالية واحفظ التالي في badPropertyExample.py.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7527_14" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">ClassWithBadProperty</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">
        self</span><span class="pun">.</span><span class="pln">someAttribute </span><span class="pun">=</span><span class="pln"> </span><span class="str">'some initial value'</span><span class="pln">

    </span><span class="lit">@property</span><span class="pln">
    </span><span class="kwd">def</span><span class="pln"> someAttribute</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">
        </span><span class="com"># نسينا هنا استخدام الشرطة السفلية (_) مما تسبب باستخدامنا للخاصية واستدعاء التابع الجالب مجددًا</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">someAttribute  </span><span class="com"># هذا يستدعي التابع الجالب مجددًا</span><span class="pln">

    </span><span class="lit">@someAttribute</span><span class="pun">.</span><span class="pln">setter
    </span><span class="kwd">def</span><span class="pln"> someAttribute</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> value</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">_someAttribute </span><span class="pun">=</span><span class="pln"> value

obj </span><span class="pun">=</span><span class="pln"> </span><span class="typ">ClassWithBadProperty</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">.</span><span class="pln">someAttribute</span><span class="pun">)</span><span class="pln">  </span><span class="com"># ينتج خطأ هنا بسبب استدعاء الدالة الجالبة للدالة الجالبة</span></pre>

<p>
	يستمر الجالب باستدعاء نفسه عند تنفيذ هذه الشيفرة إلى أن يعطي بايثون الاستثناء <code>recursionError</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7527_16" style=""><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"badPropertyExample.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">16</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">.</span><span class="pln">someAttribute</span><span class="pun">)</span><span class="pln">  </span><span class="com"># ينتج خطأ هنا بسبب استدعاء الدالة الجالبة للدالة الجالبة</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"badPropertyExample.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> someAttribute
    </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">someAttribute  </span><span class="com"># يستدعي هذا السطر الجالب مجددًا </span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"badPropertyExample.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> someAttribute
    </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">someAttribute  </span><span class="com"># يستدعي هذا السطر الجالب مجددًا </span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"badPropertyExample.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> someAttribute
    </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">someAttribute  </span><span class="com"># يستدعي هذا السطر الجالب مجددًا </span><span class="pln">
  </span><span class="pun">[</span><span class="typ">Previous</span><span class="pln"> line repeated </span><span class="lit">996</span><span class="pln"> more times</span><span class="pun">]</span><span class="pln">
</span><span class="typ">RecursionError</span><span class="pun">:</span><span class="pln"> maximum recursion depth exceeded</span></pre>

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

<h2 id="-1">
	استخدام الضوابط للتحقق من البيانات
</h2>

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

<p>
	لنحدث ملف wizcoin.py الذي أنشأناه سابقًا ليُحوّل السمات <code>galleons</code> و <code>sickles</code> و <code>knuts</code> إلى خاصيات. سنغير ضابطة هذه الخاصيات لتكون الأرقام الصحيحة الموجبة فقط صالحة. تمثل <code>WizCoin</code> كمية النقود ولا يمكن أن تحتوي نصف قطعة نقدية أو أي قيمة أقل من الصفر، سنرفع استثناء <code>WizCoinException</code> في حال حاولت شيفرة خارج الصنف أن تضبط الخاصيات <code>galleons</code> أو <code>sickles</code> أو <code>knuts</code> إلى قيمة غير صالحة .
</p>

<p>
	افتح ملف wizoin.py الذي حفظته سابقًا وعدله ليصبح على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7527_18" style=""><span class="lit">1</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">WizCoinException</span><span class="pun">(</span><span class="typ">Exception</span><span class="pun">):</span><span class="pln">
</span><span class="lit">2</span><span class="pln">     </span><span class="str">"""The wizcoin module raises this when the module is misused."""</span><span class="pln">
    </span><span class="kwd">pass</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">WizCoin</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"> galleons</span><span class="pun">,</span><span class="pln"> sickles</span><span class="pun">,</span><span class="pln"> knuts</span><span class="pun">):</span><span class="pln">
        </span><span class="str">"""Create a new WizCoin object with galleons, sickles, and knuts."""</span><span class="pln">
</span><span class="lit">3</span><span class="pln">         self</span><span class="pun">.</span><span class="pln">galleons </span><span class="pun">=</span><span class="pln"> galleons
        self</span><span class="pun">.</span><span class="pln">sickles  </span><span class="pun">=</span><span class="pln"> sickles
        self</span><span class="pun">.</span><span class="pln">knuts    </span><span class="pun">=</span><span class="pln"> knuts
        </span><span class="com"># NOTE: __init__() methods NEVER have a return statement.</span><span class="pln">

</span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">

    </span><span class="lit">@property</span><span class="pln">
</span><span class="lit">4</span><span class="pln">     </span><span class="kwd">def</span><span class="pln"> galleons</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
        </span><span class="str">"""Returns the number of galleon coins in this object."""</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">_galleons

    </span><span class="lit">@galleons</span><span class="pun">.</span><span class="pln">setter
</span><span class="lit">5</span><span class="pln">     </span><span class="kwd">def</span><span class="pln"> galleons</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">):</span><span class="pln">
</span><span class="lit">6</span><span class="pln">         </span><span class="kwd">if</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> isinstance</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">
</span><span class="lit">7</span><span class="pln">             </span><span class="kwd">raise</span><span class="pln"> </span><span class="typ">WizCoinException</span><span class="pun">(</span><span class="str">'galleons attr must be set to an int, not a '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> value</span><span class="pun">.</span><span class="pln">__class__</span><span class="pun">.</span><span class="pln">__qualname__</span><span class="pun">)</span><span class="pln">
</span><span class="lit">8</span><span class="pln">         </span><span class="kwd">if</span><span class="pln"> value </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">raise</span><span class="pln"> </span><span class="typ">WizCoinException</span><span class="pun">(</span><span class="str">'galleons attr must be a positive int, not '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> value</span><span class="pun">.</span><span class="pln">__class__</span><span class="pun">.</span><span class="pln">__qualname__</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">_galleons </span><span class="pun">=</span><span class="pln"> value

</span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span></pre>

<p>
	تضيف التغييرات الجديدة صنف <code>WizCoinException</code> الذي يرث من صنف <code>Exception</code> المبني مسبقًا في بايثون. توضح <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%82%D8%A7%D8%AA-comments-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r2026/" rel="">سلسلة توثيق النصية docstring</a> الخاصة بالصنف كيف تستخدمه وحدة <code>wizcoin</code>. تُعد هذه ممارسة جيدة <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-modules-%D9%88%D8%A7%D9%84%D8%AD%D8%B2%D9%85-packages-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r329/" rel="">لوحدات بايثون</a> يمكن أن ترفعها كائنات صنف <code>wizcoin</code> عندما يُساء استخدامها، وهكذا عندما يرفع كائن <code>WizCoin</code> أصناف <a href="https://wiki.hsoub.com/Python/exceptions" rel="external">استثناءات</a> أخرى مثل <code>ValueError</code> و <code>TypeError</code>، سيشير هذا غالبًا إلى خطأ في صنف <code>WizCoin</code>.
</p>

<p>
	ضبطنا في التابع <code>‎__‎init__()‎</code> الخاصيات <code>self.galleons</code> و <code>slef.sickles</code> و <code>self.knuts</code> إلى المعاملات الموافقة.
</p>

<p>
	أضفنا في آخر الملف تابع جالب وضابط للسمة <code>self._galleons</code> بعد التابعين <code>total()‎</code> و <code>weight()‎</code>. يعيد هذا الجالب القيمة في <code>self._galleons</code> ويتحقق التابع الضابط إذا كان القيمة المسندة إلى الخاصية <code>galleons</code> هي عدد صحيح وموجب، إذا فشل واحد من التحقيقين تُرفع <code>WizCoinException</code> برسالة خطأ، كما يمنع هذا التحقق <code>‎_galleons</code> من أن تُضبط بقيمة غير صالحة طالما تستخدم الشيفرة الخاصية <code>galleons</code>.
</p>

<p>
	لدى كل كائنات بايثون تلقائيًا سمة <code>__class__</code> التي تشير إلى صنف الكائن. بمعنى أخر، <code>__value.__class</code> هي نفس صنف الكائن الذي يعيده <code>type(value)‎</code> ، كما أنه لدى كائن الصنف هذا سمة <code>__qualname__</code> التي هي سلسلة نصية لاسم الصنف. تحديدًا هو الاسم المؤهل للصنف الذي يتضمن أسماء أي أصناف يكون كائن الصنف متداخلًا فيها. <a href="https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D8%A3%D8%B5%D9%86%D8%A7%D9%81-%D8%A7%D9%84%D9%85%D8%AA%D8%AF%D8%A7%D8%AE%D9%84%D8%A9-nested-classes-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1115/" rel="">الأصناف المتداخلة Nested classes</a> محدودة الاستخدام وخارج نطاق موضوعنا. فمثلًا إذا كانت <code>value</code> قد خزّنت الكائن <code>date</code> المعاد بالصيغة <code>datetime.date(2021, 1, 1)‎</code>، ستكون <code>__value.__class__.__qualname</code> هي السلسلة النصية <code>'date'</code>. تستخدِم رسالة الاستثناء <code>__value.__class__.__qualname</code> (في السطر 7) للوصول إلى السلسلة النصية لقيمة اسم الكائن، إذ يجعل اسم الكائن رسالة الخطأ هذه أكثر إفادة للمبرمج الذي يقرأها لأنها تحدّد أن الوسيط 'value' ليس من النوع الصحيح، وتحدد أيضًا ما هو نوعه السابق وما النوع الذي يجب أن يكون.
</p>

<p>
	ستحتاج لنسخ الشيفرة من الجالب والضابط ليستخدمها <code>‎_galleons</code> ومن أجل سمات <code>‎_sickles</code> و <code>‎_knuts</code> أيضًا، إذ تكون شيفراتهم نفسها ما عدا أنها تستخدم السمات <code>‎_sickles</code> و <code>‎_knuts</code> بدلًا من <code>‎_galleons</code> للمتغيرات الراجعة.
</p>

<h2 id="-2">
	خاصيات القراءة فقط
</h2>

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

<p>
	مثلًا، يعيد التابع <code>total()‎</code> في الصنف <code>WizCoin</code> قيمة الكائن في knuts. يمكننا تغيير ذلك من تابع عادي لخاصية القراءة فقط لأنه في النهاية لا توجد طريقة منطقية لضبط <code>total</code> لكائن <code>WizCoin</code>؛ فإذا ضبطنا <code>total</code> إلى العدد الصحيح <code>1000</code>، هل ذلك يعني ‎1000 knuts؟ أو ‎1 galleon و ‎493 knuts؟ أو أي تشكيلة أخرى؟ لهذا السبب سنجعل <code>total</code> خاصية للقراءة فقط عن طريق إضافة الشيفرة بالخط الغامق في ملف wizcoin.py:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7527_20" style=""><span class="lit">@property</span><span class="pln">
    </span><span class="kwd">def</span><span class="pln"> total</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
        </span><span class="str">"""Total value (in knuts) of all the coins in this WizCoin object."""</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">self</span><span class="pun">.</span><span class="pln">galleons </span><span class="pun">*</span><span class="pln"> </span><span class="lit">17</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">29</span><span class="pun">)</span><span class="pln"> </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">sickles </span><span class="pun">*</span><span class="pln"> </span><span class="lit">29</span><span class="pun">)</span><span class="pln"> </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">knuts</span><span class="pun">)</span><span class="pln">

    </span><span class="com"># Note that there is no setter or deleter method for `total`.</span></pre>

<p>
	بعد إضافة مزخرف التابع <code>porperty@</code> أمام <code>total()‎</code>، سيستدعي بايثون تابع <code>total()‎</code> عند الوصول إلى <code>total</code>، ولأنه لا يوجد تابع ضابط ولا حاذف، ترفع بايثون <code>AtrributeError</code> إذا حاولت أي شيفرة تعديل أو حذف <code>total</code> باستخدامه في وسيط أو تعليمة <code>del</code>على التتالي. تعتمد قيمة الخاصية <code>total</code> على قيمة الخاصيات <code>galleons</code> و <code>sickles</code> و <code>knuts</code> ولا تعتمد الخاصية على متغير الرجوع المسمى <code>‎_total</code> .
</p>

<p>
	أدخل التالي في الصَدَفة التفاعلية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7527_22" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> wizcoin
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse </span><span class="pun">=</span><span class="pln"> wizcoin</span><span class="pun">.</span><span class="typ">WizCoin</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse</span><span class="pun">.</span><span class="pln">total
</span><span class="lit">1141</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> purse</span><span class="pun">.</span><span class="pln">total </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1000</span><span class="pln">
</span><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent call last</span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="str">"&lt;stdin&gt;"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">module</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">AttributeError</span><span class="pun">:</span><span class="pln"> can</span><span class="str">'t set attribute</span></pre>

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

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

<h2 id="-3">
	أين تستخدم الخواص
</h2>

<p>
	كما رأينا في القسم السابق، تقدم الخاصيات سيطرةً أكثر على كيفية استخدام سمات الصنف، وهذه طريقة خاصة ببايثون لكتابة الشيفرة. تشير التوابع المسماة <code>‏‏‏‏‏‏‏‏getSomeAttribute()‎‏‏‏‏‏‎‎‎‎‎</code> و <code>setSomeAttribute()‎</code> أنه يجب استخدام الخاصيات بدلًا عن ذلك.
</p>

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

<ul>
	<li>
		العمليات البطيئة التي تستغرق أكثر من ثانية أو ثانيتين، مثل تنزيل أو رفع الملفات.
	</li>
	<li>
		العمليات التي لديها آثار جانبية، مثل حدوث تغييرات لسمات وكائنات أخرى.
	</li>
	<li>
		العمليات التي تتطلب وسائط إضافية لتمرر إلى عمليات الجلب أو الضبط، مثل استدعاء تابع <code>emailObj.getFileAttachment(filename)‎</code>.
	</li>
</ul>

<h2 id="-4">
	الخلاصة
</h2>

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

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

<p>
	تطبّق بايثون الخاصيات كائنية التوجه بصورةٍ مختلفة عن باقي لغات <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/programming/java/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%85%D8%A7-%D9%87%D9%8A%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-java-r1515/" rel="">جافا</a> و <a href="https://academy.hsoub.com/programming/cpp/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-c-r802/" rel="">C++</a>‎، فبدلًا من تقديم توابع جالبة وضابطة محددة، لدى بايثون خاصيات تسمح لك بتدقيق السمات وجعلها للقراءة فقط.
</p>

<p>
	ترجمة -وبتصرف- لقسم من الفصل <a href="http://inventwithpython.com/beyond/chapter17.html" rel="external nofollow">Pythonic <abbr title="Object-Oriented Programming | البرمجة كائنية التوجه"><abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr></abbr>: Properties and dunder methods</a> من كتاب <a href="https://inventwithpython.com/beyond//" rel="external nofollow">Beyond the Basic Stuff with Python</a>.
</p>

<h2 id="-5">
	اقرأ المزيد
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-python-3-r535/" rel="">الدليل السريع إلى لغة البرمجة بايثون Python 3</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/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="">البرمجة كائنية التوجه (Object Oriented Programming) في بايثون - الجزء الأول</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D9%85%D8%AE%D8%AA%D8%B5%D8%B1-%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-%D9%88%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D9%87%D8%A7-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1926/" rel="">مختصر البرمجة كائنية التوجه <abbr title="Object-Oriented Programming | البرمجة كائنية التوجه"><abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr></abbr> وتطبيقها في بايثون</a>
	</li>
	<li>
		<a href="https://wiki.hsoub.com/Python#.D8.A7.D9.84.D8.A3.D8.AE.D8.B7.D8.A7.D8.A1_.D9.88.D8.A7.D9.84.D8.A7.D8.B3.D8.AA.D8.AB.D9.86.D8.A7.D8.A1.D8.A7.D8.AA" rel="external">توثيق بايثون</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2188</guid><pubDate>Mon, 04 Dec 2023 16:00:00 +0000</pubDate></item><item><title>&#x645;&#x634;&#x627;&#x631;&#x64A;&#x639; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646; &#x639;&#x645;&#x644;&#x64A;&#x629; &#x62A;&#x646;&#x627;&#x633;&#x628; &#x627;&#x644;&#x645;&#x628;&#x62A;&#x62F;&#x626;&#x64A;&#x646;</title><link>https://academy.hsoub.com/programming/python/%D9%85%D8%B4%D8%A7%D8%B1%D9%8A%D8%B9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D9%86%D8%A7%D8%B3%D8%A8-%D8%A7%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86-r2185/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_12/-.png.0556f3c5fbe539d07f65ae1f66a3e9c1.png" /></p>
<p>
	إذا كنت من محبي لغة البرمجة بايثون وترغب في تعلمها واحترافها وتبحث عن اكواد مشاريع بايثون فهذا المقال سيوفر لك مجموعة متنوعة من مشاريع بايثون للمبتدئين الذين أنهوا تعلم أساسيات لغة بايثون ويرغبون في تعزيز معرفتهم بالتطبيق العملي والتدرب على طريقة التفكير في حل مشكلات برمجية مختلفة والاستفادة من الوحدات والمكتبات العديدة التي توفرها لغة بايثون المناسبة التي تساعد على حلها بسلاسة وسرعة.
</p>

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

<h2 id="-1">
	أهمية تنفيذ مشاريع بايثون للمبتدئين
</h2>

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

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

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

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

<h3 id="-2">
	مشروع آلة حاسبة بلغة بايثون
</h3>

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

<p>
	<strong>الدخل</strong>: رمز العملية الحسابية المطلوب إجراؤها والعددان المطلوب تنفيذ العملية عليهما (يجب أن يدخل المستخدم رمز صحيح وإلا يمكن أن تعرض له رسالة تطلب منه إدخال رمز صحيح أو تنهي البرنامج)
</p>

<p>
	<strong>الخرج</strong>: هو طباعة نتيجة العملية الحسابية.
</p>

<p>
	كود مشروع آلة حاسبة باستخدام بايثون:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3507_6" style=""><span class="com"># calculator1.py</span><span class="pln">


</span><span class="com"># دالة جمع عددين</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> add</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> num2</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> num1 </span><span class="pun">+</span><span class="pln"> num2


</span><span class="com"># دالة طرح عددين</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> subtract</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> num2</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> num1 </span><span class="pun">-</span><span class="pln"> num2


</span><span class="com"># دالة جداء عددين</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> multiplnum2</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> num2</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> num1 </span><span class="pun">*</span><span class="pln"> num2


</span><span class="com"># دالة قسمة عددين</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> divide</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> num2</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> num2 </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="str">"لا يمكنك القسمة على صفر"</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> num1 </span><span class="pun">/</span><span class="pln"> num2


</span><span class="com"># استدعاء الدالة المناسبة</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"اختر العملية الحسابيةالمطلوبة "</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"للجمع اختر 1 "</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"للطرح اختر 2 "</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"للجداء اختر 3 "</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"للقسمة اختر 4 "</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"اختر أي مفتاح آخر لأنهاء التنفيذ"</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">
    </span><span class="com"># إدخال قيمة العددين</span><span class="pln">
    choice </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"حدد العملية المطلوبة (1/2/3/4): "</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> choice </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">(</span><span class="str">"1"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"2"</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">"4"</span><span class="pun">):</span><span class="pln">
        num1 </span><span class="pun">=</span><span class="pln"> float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"Enter first number: "</span><span class="pun">))</span><span class="pln">
        num2 </span><span class="pun">=</span><span class="pln"> float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"Enter second number: "</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="str">"1"</span><span class="pun">:</span><span class="pln">
            </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> </span><span class="str">"+"</span><span class="pun">,</span><span class="pln"> num2</span><span class="pun">,</span><span class="pln"> </span><span class="str">"="</span><span class="pun">,</span><span class="pln"> add</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> num2</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="str">"2"</span><span class="pun">:</span><span class="pln">
            </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> </span><span class="str">"-"</span><span class="pun">,</span><span class="pln"> num2</span><span class="pun">,</span><span class="pln"> </span><span class="str">"="</span><span class="pun">,</span><span class="pln"> subtract</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> num2</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="str">"3"</span><span class="pun">:</span><span class="pln">
            </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> </span><span class="str">"*"</span><span class="pun">,</span><span class="pln"> num2</span><span class="pun">,</span><span class="pln"> </span><span class="str">"="</span><span class="pun">,</span><span class="pln"> multiplnum2</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> num2</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="str">"4"</span><span class="pun">:</span><span class="pln">
            </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> </span><span class="str">"/"</span><span class="pun">,</span><span class="pln"> num2</span><span class="pun">,</span><span class="pln"> </span><span class="str">"="</span><span class="pun">,</span><span class="pln"> divide</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> num2</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="str">"إنهاء التنفيذ "</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">break</span></pre>

<p>
	عند تنفيذ المشروع سنحصل على خرج مشابه لما هو مبين في الصورة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="139344" href="https://academy.hsoub.com/uploads/monthly_2023_12/---.png.3f7a74618c38c02d2dda387118455582.png" rel=""><img alt="مشروع بايثون الآلة الحاسبة" class="ipsImage ipsImage_thumbnailed" data-fileid="139344" data-ratio="86.60" data-unique="0a1u6b94j" style="width: 500px; height: auto;" width="500" src="https://academy.hsoub.com/uploads/monthly_2023_12/---.thumb.png.741a2e6573c0573714257e8f50bc57d5.png"> </a>
</p>

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

<p>
	لاحظ الكود التالي عرفنا في البداية ملف باسم math_operations.py يمثل المكتبة ويتضمن تعريف كافة العمليات الحسابية.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3507_13" style=""><span class="com"># math_operations.py</span><span class="pln">
</span><span class="com"># استيراد المكتبة</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> math_op
</span><span class="com"># استدعاء الدالة المناسبة</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"اختر العملية الحسابيةالمطلوبة "</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"للجمع اختر 1 "</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"للطرح اختر 2 "</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"للجداء اختر 3 "</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"للقسمة اختر 4 "</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"اختر أي مفتاح آخر لأنهاء التنفيذ"</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">
    </span><span class="com"># إدخال قيمة العددين</span><span class="pln">
    choice </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"حدد العملية المطلوبة (1/2/3/4): "</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> choice </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">(</span><span class="str">"1"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"2"</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">"4"</span><span class="pun">):</span><span class="pln">
        num1 </span><span class="pun">=</span><span class="pln"> float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"أدخل العدد الأول "</span><span class="pun">))</span><span class="pln">
        num2 </span><span class="pun">=</span><span class="pln"> float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"أدخل العدد الثاني  "</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="str">"1"</span><span class="pun">:</span><span class="pln">
            </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> </span><span class="str">"+"</span><span class="pun">,</span><span class="pln"> num2</span><span class="pun">,</span><span class="pln"> </span><span class="str">"="</span><span class="pun">,</span><span class="pln"> math_op</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> num2</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="str">"2"</span><span class="pun">:</span><span class="pln">
            </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> </span><span class="str">"-"</span><span class="pun">,</span><span class="pln"> num2</span><span class="pun">,</span><span class="pln"> </span><span class="str">"="</span><span class="pun">,</span><span class="pln"> math_op</span><span class="pun">.</span><span class="pln">subtract</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> num2</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="str">"3"</span><span class="pun">:</span><span class="pln">
            </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> </span><span class="str">"*"</span><span class="pun">,</span><span class="pln"> num2</span><span class="pun">,</span><span class="pln"> </span><span class="str">"="</span><span class="pun">,</span><span class="pln"> math_op</span><span class="pun">.</span><span class="pln">multiplnum2</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> num2</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="str">"4"</span><span class="pun">:</span><span class="pln">
            </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> </span><span class="str">"/"</span><span class="pun">,</span><span class="pln"> num2</span><span class="pun">,</span><span class="pln"> </span><span class="str">"="</span><span class="pun">,</span><span class="pln"> math_op</span><span class="pun">.</span><span class="pln">divide</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> num2</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="str">"إنهاء التنفيذ "</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">break</span></pre>

<p>
	ثم عرفنا ملف المشروع الأساسي calculator2.py الذي يستورد المكتبة ويستخدم وظائفها كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3507_11" style=""><span class="com"># calculator2.py</span><span class="pln">
</span><span class="com"># استيراد المكتبة</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> math_op
</span><span class="com"># استدعاء الدالة المناسبة</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"اختر العملية الحسابيةالمطلوبة "</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"للجمع اختر 1 "</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"للطرح اختر 2 "</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"للجداء اختر 3 "</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"للقسمة اختر 4 "</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"اختر أي مفتاح آخر لأنهاء التنفيذ"</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">
    </span><span class="com"># إدخال قيمة العددين</span><span class="pln">
    choice </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"حدد العملية المطلوبة (1/2/3/4): "</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> choice </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">(</span><span class="str">"1"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"2"</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">"4"</span><span class="pun">):</span><span class="pln">
        num1 </span><span class="pun">=</span><span class="pln"> float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"أدخل العدد الأول "</span><span class="pun">))</span><span class="pln">
        num2 </span><span class="pun">=</span><span class="pln"> float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"أدخل العدد الثاني  "</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="str">"1"</span><span class="pun">:</span><span class="pln">
            </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> </span><span class="str">"+"</span><span class="pun">,</span><span class="pln"> num2</span><span class="pun">,</span><span class="pln"> </span><span class="str">"="</span><span class="pun">,</span><span class="pln"> math_op</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> num2</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="str">"2"</span><span class="pun">:</span><span class="pln">
            </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> </span><span class="str">"-"</span><span class="pun">,</span><span class="pln"> num2</span><span class="pun">,</span><span class="pln"> </span><span class="str">"="</span><span class="pun">,</span><span class="pln"> math_op</span><span class="pun">.</span><span class="pln">subtract</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> num2</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="str">"3"</span><span class="pun">:</span><span class="pln">
            </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> </span><span class="str">"*"</span><span class="pun">,</span><span class="pln"> num2</span><span class="pun">,</span><span class="pln"> </span><span class="str">"="</span><span class="pun">,</span><span class="pln"> math_op</span><span class="pun">.</span><span class="pln">multiplnum2</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> num2</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="str">"4"</span><span class="pun">:</span><span class="pln">
            </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> </span><span class="str">"/"</span><span class="pun">,</span><span class="pln"> num2</span><span class="pun">,</span><span class="pln"> </span><span class="str">"="</span><span class="pun">,</span><span class="pln"> math_op</span><span class="pun">.</span><span class="pln">divide</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">,</span><span class="pln"> num2</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="str">"إنهاء التنفيذ "</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">break</span></pre>

<p>
	لتنفيذ هذا المشروع بشكل صحيح يجب أن تحفظ كل من ملف المشروع الرئيسي calculator2.py وملف المكتبة التي عرفتها math_op.py في نفس المجلد.
</p>

<p>
	<strong>توصيات حول المشروع:</strong>
</p>

<p>
	جرب أن تضيف المزيد من التحسينات على هذا المشروع بأن تعرف دوال رياضية مثل دالة حساب رفع عدد لأس، أو حساب الجذر التربيعي لعدد ما، وجرب كذلك أن تحوله إلى مشروع واجهة رسومية بالاعتماد على <a href="https://academy.hsoub.com/programming/python/%D8%A3%D9%87%D9%85-10-%D9%85%D9%83%D8%AA%D8%A8%D8%A7%D8%AA-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%AA%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%B4%D8%A7%D8%B1%D9%8A%D8%B9-%D8%A7%D9%84%D8%B5%D8%BA%D9%8A%D8%B1%D8%A9-r654/" rel="">مكتبات بايثون</a> المناسبة.
</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 id="-3">
	مشروع بايثون لطباعة سلسلة أعداد فيبوناتشي
</h3>

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

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

<p style="text-align: left;">
	F(0) = 0
</p>

<p style="text-align: left;">
	F(1) = 1
</p>

<p style="text-align: left;">
	F(2) = 0+1=1
</p>

<p style="text-align: left;">
	F(3) = 1+1=2
</p>

<p style="text-align: left;">
	F(3) = 2+1=3
</p>

<p style="text-align: left;">
	F(n) = F(n-1) + F(n-2) (n &gt; 1)
</p>

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

<p>
	<strong>الدخل</strong>: عدد عناصر السلسلة المطلوب حسابها وليكن num.
</p>

<p>
	<strong>الخرج</strong>: طباعة عناصر السلسلة.
</p>

<p>
	هناك طريقتان يمكنك من خلالهما تنفيذ هذا البرنامج، الأولى باستخدام <a href="https://academy.hsoub.com/programming/python/%D8%AD%D9%84%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1-loops-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r291/" rel="">حلقات التكرار (Loops) في بايثون</a> والثانية باستخدام <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>،
</p>

<p>
	سنكتب الكود البرمجي لمشروع بايثون يعرض سلسلة أعداد فيبوناتشي بطريقة التعاود كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3507_15" style=""><span class="com">#fibonacci-series.py</span><span class="pln">

</span><span class="com"># سلسلة أعداد فيبوناتشي</span><span class="pln">

</span><span class="kwd">def</span><span class="pln">  fibonacci</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">1</span><span class="pln">  </span><span class="kwd">or</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"> n</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">return</span><span class="pln"> fibonacci</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"> </span><span class="pun">+</span><span class="pln"> fibonacci</span><span class="pun">(</span><span class="pln">n </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">


num </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">"أدخل عددًا صحيحًا موجبًا "</span><span class="pun">))</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> num </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">print</span><span class="pun">(</span><span class="str">"العدد الذي أدخلته سالب"</span><span class="pun">)</span><span class="pln">

i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">

</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"سلسلة أعداد فيبوناتشي \n: "</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">0</span><span class="pun">,</span><span class="pln"> num</span><span class="pun">+</span><span class="lit">1</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">"F("</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> </span><span class="str">"):"</span><span class="pun">,</span><span class="pln"> fibonacci</span><span class="pun">(</span><span class="pln">i</span><span class="pun">))</span></pre>

<p>
	عند تنفيذ المشروع نحصل على الخرج التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="PNG" data-fileid="139347" href="https://academy.hsoub.com/uploads/monthly_2023_12/---.PNG.065ae8146fc2d7e9ab29341ac972c35d.PNG" rel=""><img alt="مشروع سلسلة أعداد فيبوناتشي" class="ipsImage ipsImage_thumbnailed" data-fileid="139347" data-ratio="84.33" data-unique="yii4uanqr" style="width: 600px; height: auto;" width="600" src="https://academy.hsoub.com/uploads/monthly_2023_12/---.thumb.PNG.7b0c664a79c5a208b3ee7a59e63ff2dc.PNG"> </a>
</p>

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

<h3 id="-4">
	مشروع التحقق من قوة كلمة المرور
</h3>

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

<ol>
	<li>
		يجب أن تحتوي كلمة المرور على حروف صغيرة (a-z).
	</li>
	<li>
		يجب أن تحتوي كلمة المرور على حروف كبيرة (A-Z).
	</li>
	<li>
		يجب أن تحتوي كلمة المرور على محارف خاصة (!@#$^%).
	</li>
	<li>
		يجب أن تحتوي كلمة المرور على أرقام (0-9).
	</li>
	<li>
		يجب أن لا يقل طول الكلمة عن 8 محارف ولا يزيد على 20 محرف
	</li>
</ol>

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

<p>
	أسهل طريقة لتحقيق هذا المشروع هي باستخدام مفهوم <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="">التعابير النمطية في البرمجة regular expression </a>والمعروفة اختصارًا باسم Regex، فمن خلالها يمكن تعريف نمط بحث للتحقق من قوة كلمة المرور بالشكل التالي:
</p>

<p>
	<code>^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*``#?&amp;])[A-Za-z\d@$!#%*?&amp;]{6,20}$</code>
</p>

<p>
	يفحص هذا التعبير النمطي قوة كلمة المرور حيث يبدأ بالرمز <code>^</code> الذي يعني أن الاختبار يجب أن يبدأ من بداية كلمة المرور وبعدها يليه <code>(?=.*[a-z])</code> الذي يتحقق من وجود حرف صغير على الأقل في كلمة المرور ثم القسم <code>(?=.*[A-Z])</code> الذي يتحقق من وجود حرف كبير على الأقل في كلمة المرور ثم <code>(?=.*\d)</code> الذي يتأكد من وجود رقم واحد على الأقل فيها والقسم <code>(?=.*[@$!%*#?&amp;])</code> للتأكد من وجود محرف خاص على الأقل في كلمة المرور والقسم <code>[A-Za-z\d@$!#%*?&amp;]{6,20}</code> للتحقق من أن طول كلمة المرور بين 8 إلى 20 محرف وأنهينا التعبير النمطي بكتابة الرمز <code>$</code> الذي يعني أن الاختبار يستمر حتى نهاية كلمة المرور.
</p>

<p>
	وللتحقق من مطابقة كلمة المرور لهذا النمط في مشروعنا سنعتمد على مكتبة بايثون المسماة <a href="https://docs.python.org/3/library/re.html" rel="external nofollow">re</a> وهي مكتبة قياسية في بايثون تساعدك على تعريف التعابير النمطية والتحقق من مطابقة سلسلة ما لنمط معين.
</p>

<p>
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="450" id="ips_uid_7033_6" src="https://academy.hsoub.com/applications/core/interface/index.html" title="ما هي التعابير النمطية" width="800" data-embed-src="https://www.youtube.com/embed/xvnnAX7zYAw"></iframe>
</p>

<p>
	<strong>الدخل</strong>: كلمة المرور المطلوب فحصها.
</p>

<p>
	<strong>الخرج</strong>: طباعة رسالة تظهر فيما إذا كانت كلمة المرور قوية أم ضعيفة.
</p>

<p>
	مشروع بايثون للتحقق من قوة كلمة المرور:
</p>

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

</span><span class="kwd">def</span><span class="pln"> is_strong_password</span><span class="pun">(</span><span class="pln">pwd</span><span class="pun">):</span><span class="pln">
    pattern </span><span class="pun">=</span><span class="pln"> </span><span class="str">'^[a-z]+[A-Z]+[!@#$^%]+[0-9]+$'</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> bool</span><span class="pun">(</span><span class="pln">re</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="pln">pattern</span><span class="pun">,</span><span class="pln"> pwd</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">
    password </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"أدخل كلمة المرور: "</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> is_strong_password</span><span class="pun">(</span><span class="pln">password</span><span class="pun">):</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="str">"كلمة المرور قوية"</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">break</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="str">"\nكلمة المرور ضعيفة، أدخل واحدة أخرى"</span><span class="pun">)</span></pre>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="PNG" data-fileid="139343" href="https://academy.hsoub.com/uploads/monthly_2023_12/-----.PNG.4400c24efe4a3dc39f5f4aeca9cab852.PNG" rel=""><img alt="مشروع التحقق من قوة كلمة المرور" class="ipsImage ipsImage_thumbnailed" data-fileid="139343" data-unique="gomykkit0" src="https://academy.hsoub.com/uploads/monthly_2023_12/-----.PNG.4400c24efe4a3dc39f5f4aeca9cab852.PNG"> </a>
</p>

<p>
	<strong>توصيات حول المشروع</strong>:
</p>

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

<h3 id="-5">
	مشروع حساب عدد الأحرف الصوتية والفراغات والكلمات في نص
</h3>

<p>
	يحتاج أي مبتدئ إلى تنفيذ عدة مشاريع بايثون تعالج السلاسل النصية وتستخدم <a href="https://docs.python.org/3/library/string.html" rel="external nofollow">دوال النصوص</a> المناسبة للحصول على النتائج المطلوبة، في هذا المشروع سنكتب كود بايثون يطلب من المستخدم إدخال نص معين باللغة الإنجليزية ونحسب عدد الأحرف الصوتية الواردة فيه وعدد فراغاته وعدد كلماته.
</p>

<p>
	بالنسبة للأحرف الصوتية فهي كما خمسة حروف a وe i و o و u ويجب أن تراعي وجود الأحرف الصغيرة والكبيرة أو يمكنك بشكل بديل تحويل النص المدخل من قبل المستخدم بالكامل إلى حروف صغيرة أو كبيرة لتسهيل عملية البحث.
</p>

<p>
	أما بالنسبة للفراغات فيمكن أن تتحقق من وجود فراغ في نص ما بسهولة باستخدام الدالة الجاهزة <code>isspace</code>و ويمكن كذلك حساب عدد الكلمات بعدة طرق ومن أسهل هذه الطرق الاستعانة بالدالة <code>split</code> التي تقسم الجملة إلى كلمات باستخدام الفراغ كفاصل وتعيد <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%D9%82%D9%88%D8%A7%D8%A6%D9%85-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-r733/" rel="">قائمة List</a> بكافة هذه الكلمات وبعدها نستخدم الدالة <code>len</code> التي تعيد لنا عدد عناصر هذه القائمة.
</p>

<p>
	<strong>الدخل</strong>: هو النص المطلوب البحث فيه
</p>

<p>
	<strong>الخرج</strong>: عدد الأحرف الصوتية والفراغات والكلمات في هذا النص.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3507_20" style=""><span class="com"># حساب عدد الفراغات والكلمات والأحرف الصوتية في سلسلة نصية</span><span class="pln">

countv</span><span class="pun">=</span><span class="lit">0</span><span class="pln">
countw</span><span class="pun">=</span><span class="lit">0</span><span class="pln">
counts</span><span class="pun">=</span><span class="lit">0</span><span class="pln">

input_sentence</span><span class="pun">=</span><span class="pln">input</span><span class="pun">(</span><span class="str">"أدخل النص هنا: "</span><span class="pun">)</span><span class="pln">

</span><span class="com"># عدد الأحرف الصوتية والفراغات</span><span class="pln">
sentence</span><span class="pun">=</span><span class="pln">input_sentence</span><span class="pun">.</span><span class="pln">lower</span><span class="pun">()</span><span class="pln">
vowles</span><span class="pun">=[</span><span class="str">"a"</span><span class="pun">,</span><span class="str">"e"</span><span class="pun">,</span><span class="str">"i"</span><span class="pun">,</span><span class="str">"o"</span><span class="pun">,</span><span class="str">"u"</span><span class="pun">]</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> char </span><span class="kwd">in</span><span class="pln"> sentence</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> char </span><span class="kwd">in</span><span class="pln"> vowles</span><span class="pun">:</span><span class="pln">
        countv</span><span class="pun">=</span><span class="pln">countv</span><span class="pun">+</span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">char</span><span class="pun">.</span><span class="pln">isspace</span><span class="pun">()):</span><span class="pln">
        counts</span><span class="pun">=</span><span class="pln">counts</span><span class="pun">+</span><span class="lit">1</span><span class="pln">

</span><span class="com"># عدد الكلمات</span><span class="pln">
countw </span><span class="pun">=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">input_sentence</span><span class="pun">.</span><span class="pln">split</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="str">" عدد الأحرف الصوتية :"</span><span class="pun">,</span><span class="pln"> countv</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">" عدد الكلمات :"</span><span class="pun">,</span><span class="pln"> countw</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">" عدد الفراغات :"</span><span class="pun">,</span><span class="pln"> counts</span><span class="pun">)</span></pre>

<p>
	عند تنفيذ البرنامج على السلسلة النصية "Learn PYTHON with Welcome to Hsoub Academy" نحصل على الخرج التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="PNG" data-fileid="139342" href="https://academy.hsoub.com/uploads/monthly_2023_12/----.PNG.595d3562dd76ecd15d2dbf805ac713aa.PNG" rel=""><img alt="مشروع البحث في سلسلة نصية" class="ipsImage ipsImage_thumbnailed" data-fileid="139342" data-unique="jl54cfrf8" src="https://academy.hsoub.com/uploads/monthly_2023_12/----.PNG.595d3562dd76ecd15d2dbf805ac713aa.PNG"> </a>
</p>

<p>
	<strong>توصيات حول المشروع:</strong>
</p>

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

<h3 id="-6">
	مشروع حاسبة الزكاة
</h3>

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

<p>
	بالطبع قيمة النصاب المستخدمة هنا ليست ثابتة وهي تتغير بحسب سعر الذهب أو الفضة وحساب المبلغ الدقيق للزكاة يعتمد على العديد من العوامل التي يجب أخذها بالحسبان، لكن الهدف من مشروعنا البسيط هذا هي تعلم إنشاء مشاريع بايثون من خلال واجهة رسومية، وأسهل طريقة لبناء واجهة المستخدم الرسومية هو تعلم طريقة <a href="https://academy.hsoub.com/programming/python/%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-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-tkinter-r1501/" rel="">بناء واجهات مستخدم رسومية في بايثون باستخدام المكتبة Tkinter</a> فهي مكتبة قياسية وسهلة الاستخدام وتتيح لك إنشاء نوافذ وأزرار وحقول إدخال وغيرها من عناصر واجهة المستخدم بسرعة ومرونة كبيرة.
</p>

<p>
	<strong>الدخل</strong>: قيمة المال المطلوب حساب زكاته، وفي حال أدخل المستخدم قيمة أموال غير صحيحة كأن يدخل نصًا بدلاً من رقم يجب أن تظهر له رسالة خطأ تطالبه بإدخال قيمة صحيحة.
</p>

<p>
	<strong>الخرج</strong>: عرض قيمة الزكاة المستحقة للمال إذا تجاوز النصاب.
</p>

<p>
	إليك مشروع بايثون لحساب مقدار زكاة المال:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3507_22" style=""><span class="com"># مشروع بايثون لحساب زكاة المال</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">from</span><span class="pln"> tkinter </span><span class="kwd">import</span><span class="pln"> messagebox
</span><span class="com"># إنشاء واجهة المستخدم</span><span class="pln">
window </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Tk</span><span class="pun">()</span><span class="pln">
window</span><span class="pun">.</span><span class="pln">geometry</span><span class="pun">(</span><span class="str">"600x350"</span><span class="pun">)</span><span class="pln">
window</span><span class="pun">.</span><span class="pln">resizable</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
window</span><span class="pun">.</span><span class="pln">config</span><span class="pun">(</span><span class="pln">bg</span><span class="pun">=</span><span class="str">"lightblue"</span><span class="pun">)</span><span class="pln">
window</span><span class="pun">.</span><span class="pln">title</span><span class="pun">(</span><span class="str">"حاسبة زكاة المال"</span><span class="pun">)</span><span class="pln">
</span><span class="com"># نصاب الزكاة بالدولار</span><span class="pln">
nisab </span><span class="pun">=</span><span class="pln"> </span><span class="lit">442</span><span class="pln">
</span><span class="com"># إنشاء متغير لتخزين قيمة أموالك</span><span class="pln">
money </span><span class="pun">=</span><span class="pln"> </span><span class="typ">DoubleVar</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"> calculate_zakat</span><span class="pun">():</span><span class="pln">
    </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
        money </span><span class="pun">=</span><span class="pln"> float</span><span class="pun">(</span><span class="pln">money_entry</span><span class="pun">.</span><span class="pln">get</span><span class="pun">())</span><span class="pln">
        zakat_amount </span><span class="pun">=</span><span class="pln"> money </span><span class="pun">*</span><span class="pln"> </span><span class="lit">0.025</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> money </span><span class="pun">&gt;</span><span class="pln"> nisab </span><span class="kwd">else</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
        result_label</span><span class="pun">.</span><span class="pln">config</span><span class="pun">(</span><span class="pln">
            text</span><span class="pun">=</span><span class="pln">f</span><span class="str">"قيمة الزكاة الواجبة عليك هي: {zakat_amount:.2f} دولار"</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">
        messagebox</span><span class="pun">.</span><span class="pln">showerror</span><span class="pun">(</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="typ">Label</span><span class="pun">(</span><span class="pln">
    window</span><span class="pun">,</span><span class="pln">
    text</span><span class="pun">=</span><span class="str">"أدخل قيمة أموالك بالدولار"</span><span class="pun">,</span><span class="pln">
    font</span><span class="pun">=</span><span class="str">"Tahoma 14"</span><span class="pun">,</span><span class="pln">
    fg</span><span class="pun">=</span><span class="str">"gray"</span><span class="pun">,</span><span class="pln">
    justify</span><span class="pun">=</span><span class="str">"right"</span><span class="pun">,</span><span class="pln">
</span><span class="pun">).</span><span class="pln">place</span><span class="pun">(</span><span class="pln">x</span><span class="pun">=</span><span class="lit">200</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">=</span><span class="lit">20</span><span class="pun">)</span><span class="pln">
money_entry </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Entry</span><span class="pun">(</span><span class="pln">window</span><span class="pun">,</span><span class="pln"> textvariable</span><span class="pun">=</span><span class="pln">money</span><span class="pun">,</span><span class="pln"> font</span><span class="pun">=</span><span class="str">"tahomab 12"</span><span class="pun">)</span><span class="pln">
money_entry</span><span class="pun">.</span><span class="pln">place</span><span class="pun">(</span><span class="pln">x</span><span class="pun">=</span><span class="lit">200</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">=</span><span class="lit">70</span><span class="pun">)</span><span class="pln">

</span><span class="com"># إنشاء زر الحساب</span><span class="pln">
calculate_button </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Button</span><span class="pun">(</span><span class="pln">
    window</span><span class="pun">,</span><span class="pln">
    text</span><span class="pun">=</span><span class="str">"حساب الزكاة"</span><span class="pun">,</span><span class="pln">
    font</span><span class="pun">=</span><span class="str">"tahoma 14 bold"</span><span class="pun">,</span><span class="pln">
    bg</span><span class="pun">=</span><span class="str">"lightgreen"</span><span class="pun">,</span><span class="pln">
    padx</span><span class="pun">=</span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    command</span><span class="pun">=</span><span class="pln">calculate_zakat</span><span class="pun">,</span><span class="pln">
    justify</span><span class="pun">=</span><span class="str">"right"</span><span class="pun">,</span><span class="pln">
</span><span class="pun">)</span><span class="pln">
calculate_button</span><span class="pun">.</span><span class="pln">place</span><span class="pun">(</span><span class="pln">x</span><span class="pun">=</span><span class="lit">220</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">=</span><span class="lit">120</span><span class="pun">)</span><span class="pln">

</span><span class="com"># إنشاء تسمية لعرض النتيجة</span><span class="pln">
result_label </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Label</span><span class="pun">(</span><span class="pln">
    window</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">""</span><span class="pun">,</span><span class="pln"> font</span><span class="pun">=</span><span class="str">"tahoma 14 bold"</span><span class="pun">,</span><span class="pln"> bg</span><span class="pun">=</span><span class="str">"lightblue"</span><span class="pun">,</span><span class="pln"> justify</span><span class="pun">=</span><span class="str">"right"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">
result_label</span><span class="pun">.</span><span class="pln">place</span><span class="pun">(</span><span class="pln">x</span><span class="pun">=</span><span class="lit">100</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">=</span><span class="lit">180</span><span class="pun">)</span><span class="pln">

window</span><span class="pun">.</span><span class="pln">mainloop</span><span class="pun">()</span></pre>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="PNG" data-fileid="139345" href="https://academy.hsoub.com/uploads/monthly_2023_12/---.PNG.1c5333cc0fbe60ea7659b12b7c33e16c.PNG" rel=""><img alt="مشروع حاسبة زكاة المال" class="ipsImage ipsImage_thumbnailed" data-fileid="139345" data-ratio="64.67" data-unique="ka63t2hj5" style="width: 600px; height: auto;" width="600" src="https://academy.hsoub.com/uploads/monthly_2023_12/---.PNG.1c5333cc0fbe60ea7659b12b7c33e16c.PNG"> </a>
</p>

<p>
	<strong>توصيات حول المشروع:</strong>
</p>

<p>
	جرب أن تحسن مظهر الواجهة الرسومية للمشروع من خلال استخدام مكتبة أخرى غير <a href="https://docs.python.org/3/library/tkinter.html" rel="external nofollow">tkinter</a> لتصميم الواجهة الرسومية للمشروع فهناك مكتبات أكثر احترافية مثل مكتبة PyQt5 أو Kivy.
</p>


<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			دورة الذكاء الاصطناعي
		</p>

		<p class="banner-subtitle">
			احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة.
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://academy.hsoub.com/learn/artificial-intelligence" rel="">اشترك الآن</a>
		</div>
	</div>

	<div class="banner-img">
		<a href="https://academy.hsoub.com/learn/artificial-intelligence" rel=""><img alt="دورة الذكاء الاصطناعي AI" src="https://academy.hsoub.com/learn/assets/images/courses/artificial-intelligence.png"></a>
	</div>
</div>


<h3 id="-7">
	مشروع ساعة رقمية
</h3>

<p>
	يهدف هذا المشروع من مشاريع باثيون Python للمبتدئين إلى تعليم المبرمج المبتدئ لكيفية إنشاء تطبيق جهة رسومية يعرض لك التوقيت المحلي والتوقيت العالمي GMT بالاستفادة من مكتبات بايثون المساعدة كما وكيفية تحديث الواجهة الرسومية كل ثانية لتحديث الساعة وجعلها تظهر لنا الوقت الحالي بدقة.
</p>

<p>
	يمكن تحقيق المشروع المطلوب من خلال إنشاء واجهة رسومية بسيطو باستخدام المكتبة القياسية tkinter والمكتبة القياسية <a href="https://docs.python.org/3/library/time.html" rel="external nofollow">time</a> للوصول إلى معلومات الوقت وتنسيقه بالشكل المناسب.
</p>

<p>
	<strong>الدخل</strong>: لا يحتاج المشروع للحصول على أي مدخلات من المستخدم
</p>

<p>
	<strong>الخرج</strong>: عرض الساعة بالتوقيت المحلي والعالمي وتنسيقها بالشكل المطلوب
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3507_25" style=""><span class="com"># مشروع بايثون لعرض التوقيت المحلي والعالمي</span><span class="pln">
</span><span class="com"># digital-clock.py</span><span class="pln">
</span><span class="com"># استيراد الوحدات المطلوبة</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">from</span><span class="pln"> time </span><span class="kwd">import</span><span class="pln"> strftime</span><span class="pun">,</span><span class="pln"> gmtime</span><span class="pun">,</span><span class="pln">localtime

</span><span class="com"># إنشاء نافذة رئيسية</span><span class="pln">
window </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Tk</span><span class="pun">()</span><span class="pln">
window</span><span class="pun">.</span><span class="pln">title</span><span class="pun">(</span><span class="str">"مشروع بايثون لعرض التوقيت المحلي والعالمي"</span><span class="pun">)</span><span class="pln">
window</span><span class="pun">.</span><span class="pln">configure</span><span class="pun">(</span><span class="pln">background</span><span class="pun">=</span><span class="str">"lavender"</span><span class="pun">)</span><span class="pln">
</span><span class="com">#إنشاء نافذة بأبعاد ثابتة</span><span class="pln">
window</span><span class="pun">.</span><span class="pln">geometry</span><span class="pun">(</span><span class="str">"510x250"</span><span class="pun">)</span><span class="pln">
window</span><span class="pun">.</span><span class="pln">resizable</span><span class="pun">(</span><span class="kwd">False</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">False</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"> get_time</span><span class="pun">():</span><span class="pln">
    </span><span class="com"># توقيت GMT</span><span class="pln">
    </span><span class="com"># %I نظام 12 ساعة</span><span class="pln">
    </span><span class="com"># %M الدقائق</span><span class="pln">
    </span><span class="com"># %S الثواني</span><span class="pln">
    </span><span class="com"># %p تعرض AM / PM</span><span class="pln">
    timeFormat1 </span><span class="pun">=</span><span class="pln"> strftime</span><span class="pun">(</span><span class="str">"%I:%M:%S %p"</span><span class="pun">,</span><span class="pln"> gmtime</span><span class="pun">())</span><span class="pln">
    clock_g</span><span class="pun">.</span><span class="pln">config</span><span class="pun">(</span><span class="pln">text</span><span class="pun">=</span><span class="str">"GMT: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> timeFormat1</span><span class="pun">)</span><span class="pln">
    </span><span class="com"># توقيت محلي بتنسيق 12 ساعة</span><span class="pln">
    timeFormat2 </span><span class="pun">=</span><span class="pln"> strftime</span><span class="pun">(</span><span class="str">"%I:%M:%S %p"</span><span class="pun">,</span><span class="pln">localtime</span><span class="pun">())</span><span class="pln">
    clock_l</span><span class="pun">.</span><span class="pln">config</span><span class="pun">(</span><span class="pln">text</span><span class="pun">=</span><span class="str">"LOC: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> timeFormat2</span><span class="pun">)</span><span class="pln">
    </span><span class="com"># جدولة تكرار استدعاء الدالة كل 1000 ميلي ثانية</span><span class="pln">
    window</span><span class="pun">.</span><span class="pln">after</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">,</span><span class="pln"> get_time</span><span class="pun">)</span><span class="pln">


clock_l </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Label</span><span class="pun">(</span><span class="pln">window</span><span class="pun">,</span><span class="pln"> font</span><span class="pun">=</span><span class="str">"Verdana 37 bold"</span><span class="pun">,</span><span class="pln"> pady</span><span class="pun">=</span><span class="lit">30</span><span class="pun">,</span><span class="pln"> bg</span><span class="pun">=</span><span class="str">"lavender"</span><span class="pun">)</span><span class="pln">
clock_l</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="pln">TOP</span><span class="pun">)</span><span class="pln">

clock_g </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Label</span><span class="pun">(</span><span class="pln">window</span><span class="pun">,</span><span class="pln"> font</span><span class="pun">=</span><span class="str">"Verdana 37 bold"</span><span class="pun">,</span><span class="pln"> pady</span><span class="pun">=</span><span class="lit">30</span><span class="pun">,</span><span class="pln"> bg</span><span class="pun">=</span><span class="str">"pink"</span><span class="pun">)</span><span class="pln">
clock_g</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="pln">BOTTOM</span><span class="pun">)</span><span class="pln">

</span><span class="com"># استدعاء دالة عرض الوقت</span><span class="pln">
get_time</span><span class="pun">()</span><span class="pln">

</span><span class="com"># تشغيل النافذة الرئيسية</span><span class="pln">
mainloop</span><span class="pun">()</span></pre>

<p>
	عند تنفيذ المشروع ستظهر لك الواجهة التالية التي تعرض الساعة بالتوقيت المحلي وبتوقيت غرينتش
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="139346" href="https://academy.hsoub.com/uploads/monthly_2023_12/--.png.ba030e1c7b0a0d6bab6f43d5dd71ca26.png" rel=""><img alt="مشروع ساعة رقمية" class="ipsImage ipsImage_thumbnailed" data-fileid="139346" data-ratio="56.00" data-unique="0976oev76" style="width: 500px; height: auto;" width="500" src="https://academy.hsoub.com/uploads/monthly_2023_12/--.png.ba030e1c7b0a0d6bab6f43d5dd71ca26.png"> </a>
</p>

<p>
	<strong>توصيات حول المشروع:</strong>
</p>

<p>
	جرب تطوير مشروع بايثون الحالي واعرض الوقت وكذلك التاريخ بتنسيقات مختلفة وجرب استخدام مكتبات بايثون أخرى للتعامل مع الوقت مثل الوحدة <a href="https://docs.python.org/3/library/datetime.html" rel="external nofollow">datetime</a> وتعرف على الفرق بينها وبين الوحدة time.
</p>

<h3 id="-8">
	مشروع حل معادلة درجة ثانية ورسم خطها البياني
</h3>

<p>
	في مشروع بايثون التالي سنقوم بإنشاء تطبيق واجهة مستخدم رسومية لحل معادلة رياضية من الدرجة الثانية أو ما يعرف <a href="https://ar.wikipedia.org/wiki/%D9%85%D8%B9%D8%A7%D8%AF%D9%84%D8%A9_%D8%AA%D8%B1%D8%A8%D9%8A%D8%B9%D9%8A%D8%A9" rel="external nofollow">بالمعادلة التربيعية</a> بطريقة المميز delta ونرسم خطها البياني الذي يكون عادة على شكل قطع مكافئ، وسنستخدم كل من المكتبة Tkinter لبناء واجهة المستخدم الرسومية والمكتبة <a href="https://matplotlib.org/" rel="external nofollow">matplotlib</a> لرسم الخط البياني.
</p>

<p>
	<strong>الدخل</strong>: معاملات المعادلة a و b و c
</p>

<p>
	<strong>الخرج</strong>: عرض حلول المعادلة x1 و x2 بحسب قيمة المميز ورسم خطها البياني.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3507_28" style=""><span class="com"># quadratic-equation.py</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><span class="kwd">from</span><span class="pln"> tkinter </span><span class="kwd">import</span><span class="pln"> messagebox
</span><span class="kwd">from</span><span class="pln"> matplotlib</span><span class="pun">.</span><span class="pln">figure </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Figure</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> matplotlib</span><span class="pun">.</span><span class="pln">backends</span><span class="pun">.</span><span class="pln">backend_tkagg </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">FigureCanvasTkAgg</span><span class="pln">

</span><span class="com"># تعريف دالة لحساب جذور المعادلة</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> solve_quadratic</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">,</span><span class="pln"> c</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
        a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">,</span><span class="pln"> c </span><span class="pun">=</span><span class="pln"> float</span><span class="pun">(</span><span class="pln">a</span><span class="pun">),</span><span class="pln"> float</span><span class="pun">(</span><span class="pln">b</span><span class="pun">),</span><span class="pln"> float</span><span class="pun">(</span><span class="pln">c</span><span class="pun">)</span><span class="pln">
        delta </span><span class="pun">=</span><span class="pln"> b</span><span class="pun">**</span><span class="lit">2</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"> a </span><span class="pun">*</span><span class="pln"> c
        </span><span class="kwd">if</span><span class="pln"> delta </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">
            x1 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(-</span><span class="pln">b </span><span class="pun">+</span><span class="pln"> delta</span><span class="pun">**</span><span class="lit">0.5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="lit">2</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> a</span><span class="pun">)</span><span class="pln">
            x2 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(-</span><span class="pln">b </span><span class="pun">-</span><span class="pln"> delta</span><span class="pun">**</span><span class="lit">0.5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="lit">2</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> a</span><span class="pun">)</span><span class="pln">
            x1_rounded </span><span class="pun">=</span><span class="pln"> round</span><span class="pun">(</span><span class="pln">x1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln">
            x2_rounded </span><span class="pun">=</span><span class="pln"> round</span><span class="pun">(</span><span class="pln">x2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> f</span><span class="str">"x1= {x1_rounded}, x2={x2_rounded}"</span><span class="pln">
        </span><span class="kwd">elif</span><span class="pln"> delta </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</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">b </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="lit">2</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> a</span><span class="pun">)</span><span class="pln">
            x_rounded </span><span class="pun">=</span><span class="pln"> round</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> f</span><span class="str">"x= {x_rounded}"</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"> </span><span class="str">"لا يوجد حلول حقيقة للمعادلة"</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">return</span><span class="pln"> </span><span class="str">"أدخل قيم صحيحة للمعاملات"</span><span class="pln">

</span><span class="com"># تعريف دالة لرسم المعادلة</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> plot_quadratic</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">,</span><span class="pln"> c</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
        a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">,</span><span class="pln"> c </span><span class="pun">=</span><span class="pln"> float</span><span class="pun">(</span><span class="pln">a</span><span class="pun">),</span><span class="pln"> float</span><span class="pun">(</span><span class="pln">b</span><span class="pun">),</span><span class="pln"> float</span><span class="pun">(</span><span class="pln">c</span><span class="pun">)</span><span class="pln">
        x </span><span class="pun">=</span><span class="pln"> range</span><span class="pun">(-</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">11</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">a </span><span class="pun">*</span><span class="pln"> x_val</span><span class="pun">**</span><span class="lit">2</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> b </span><span class="pun">*</span><span class="pln"> x_val </span><span class="pun">+</span><span class="pln"> c </span><span class="kwd">for</span><span class="pln"> x_val </span><span class="kwd">in</span><span class="pln"> x</span><span class="pun">]</span><span class="pln">

        fig </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Figure</span><span class="pun">(</span><span class="pln">figsize</span><span class="pun">=(</span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">),</span><span class="pln"> dpi</span><span class="pun">=</span><span class="lit">100</span><span class="pun">)</span><span class="pln">
        ax </span><span class="pun">=</span><span class="pln"> fig</span><span class="pun">.</span><span class="pln">add_subplot</span><span class="pun">(</span><span class="lit">111</span><span class="pun">)</span><span class="pln">
        ax</span><span class="pun">.</span><span class="pln">plot</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">

        canvas </span><span class="pun">=</span><span class="pln"> </span><span class="typ">FigureCanvasTkAgg</span><span class="pun">(</span><span class="pln">fig</span><span class="pun">,</span><span class="pln"> master</span><span class="pun">=</span><span class="pln">window</span><span class="pun">)</span><span class="pln">
        canvas_widget </span><span class="pun">=</span><span class="pln"> canvas</span><span class="pun">.</span><span class="pln">get_tk_widget</span><span class="pun">()</span><span class="pln">
        canvas_widget</span><span class="pun">.</span><span class="pln">grid</span><span class="pun">(</span><span class="pln">row</span><span class="pun">=</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">=</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> columnspan</span><span class="pun">=</span><span class="lit">3</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">
        messagebox</span><span class="pun">.</span><span class="pln">showerror</span><span class="pun">(</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="kwd">def</span><span class="pln"> calculate</span><span class="pun">():</span><span class="pln">
    a_val </span><span class="pun">=</span><span class="pln"> a_entry</span><span class="pun">.</span><span class="pln">get</span><span class="pun">()</span><span class="pln">
    b_val </span><span class="pun">=</span><span class="pln"> b_entry</span><span class="pun">.</span><span class="pln">get</span><span class="pun">()</span><span class="pln">
    c_val </span><span class="pun">=</span><span class="pln"> c_entry</span><span class="pun">.</span><span class="pln">get</span><span class="pun">()</span><span class="pln">

    result </span><span class="pun">=</span><span class="pln"> solve_quadratic</span><span class="pun">(</span><span class="pln">a_val</span><span class="pun">,</span><span class="pln"> b_val</span><span class="pun">,</span><span class="pln"> c_val</span><span class="pun">)</span><span class="pln">
    result_label</span><span class="pun">.</span><span class="pln">config</span><span class="pun">(</span><span class="pln">text</span><span class="pun">=</span><span class="pln">result</span><span class="pun">)</span><span class="pln">

    plot_quadratic</span><span class="pun">(</span><span class="pln">a_val</span><span class="pun">,</span><span class="pln"> b_val</span><span class="pun">,</span><span class="pln"> c_val</span><span class="pun">)</span><span class="pln">


</span><span class="com"># إنشاء الواجهة الرسومية</span><span class="pln">

window </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">
window</span><span class="pun">.</span><span class="pln">title</span><span class="pun">(</span><span class="str">"حل معادلة درجة ثانية"</span><span class="pun">)</span><span class="pln">
window</span><span class="pun">.</span><span class="pln">geometry</span><span class="pun">(</span><span class="str">"800x600+100+50"</span><span class="pun">)</span><span class="pln">


a_label </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">window</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"a:"</span><span class="pun">,</span><span class="pln"> font</span><span class="pun">=(</span><span class="str">"tahoma"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">12</span><span class="pun">))</span><span class="pln">
a_label</span><span class="pun">.</span><span class="pln">grid</span><span class="pun">(</span><span class="pln">row</span><span class="pun">=</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">=</span><span class="lit">0</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"> pady</span><span class="pun">=</span><span class="lit">10</span><span class="pun">)</span><span class="pln">
a_entry </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">window</span><span class="pun">,</span><span class="pln"> font</span><span class="pun">=(</span><span class="str">"tahoma"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">12</span><span class="pun">))</span><span class="pln">
a_entry</span><span class="pun">.</span><span class="pln">grid</span><span class="pun">(</span><span class="pln">row</span><span class="pun">=</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">=</span><span class="lit">1</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"> pady</span><span class="pun">=</span><span class="lit">10</span><span class="pun">)</span><span class="pln">

b_label </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">window</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"b:"</span><span class="pun">,</span><span class="pln"> font</span><span class="pun">=(</span><span class="str">"tahoma"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">12</span><span class="pun">))</span><span class="pln">
b_label</span><span class="pun">.</span><span class="pln">grid</span><span class="pun">(</span><span class="pln">row</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">=</span><span class="lit">0</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"> pady</span><span class="pun">=</span><span class="lit">10</span><span class="pun">)</span><span class="pln">
b_entry </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">window</span><span class="pun">,</span><span class="pln"> font</span><span class="pun">=(</span><span class="str">"tahoma"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">12</span><span class="pun">))</span><span class="pln">
b_entry</span><span class="pun">.</span><span class="pln">grid</span><span class="pun">(</span><span class="pln">row</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">=</span><span class="lit">1</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"> pady</span><span class="pun">=</span><span class="lit">10</span><span class="pun">)</span><span class="pln">

c_label </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">window</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"c:"</span><span class="pun">,</span><span class="pln"> font</span><span class="pun">=(</span><span class="str">"tahoma"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">12</span><span class="pun">))</span><span class="pln">
c_label</span><span class="pun">.</span><span class="pln">grid</span><span class="pun">(</span><span class="pln">row</span><span class="pun">=</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">=</span><span class="lit">0</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"> pady</span><span class="pun">=</span><span class="lit">10</span><span class="pun">)</span><span class="pln">
c_entry </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">window</span><span class="pun">,</span><span class="pln"> font</span><span class="pun">=(</span><span class="str">"tahoma"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">12</span><span class="pun">))</span><span class="pln">
c_entry</span><span class="pun">.</span><span class="pln">grid</span><span class="pun">(</span><span class="pln">row</span><span class="pun">=</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">=</span><span class="lit">1</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"> pady</span><span class="pun">=</span><span class="lit">10</span><span class="pun">)</span><span class="pln">

calculate_button </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">
    window</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Calculate"</span><span class="pun">,</span><span class="pln"> command</span><span class="pun">=</span><span class="pln">calculate</span><span class="pun">,</span><span class="pln"> font</span><span class="pun">=(</span><span class="str">"tahoma"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">12</span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span><span class="pln">
calculate_button</span><span class="pun">.</span><span class="pln">grid</span><span class="pun">(</span><span class="pln">row</span><span class="pun">=</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">=</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> columnspan</span><span class="pun">=</span><span class="lit">2</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"> pady</span><span class="pun">=</span><span class="lit">10</span><span class="pun">)</span><span class="pln">

result_label </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">window</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">""</span><span class="pun">,</span><span class="pln"> font</span><span class="pun">=(</span><span class="str">"tahoma"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">14</span><span class="pun">))</span><span class="pln">
result_label</span><span class="pun">.</span><span class="pln">grid</span><span class="pun">(</span><span class="pln">row</span><span class="pun">=</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">=</span><span class="lit">2</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"> pady</span><span class="pun">=</span><span class="lit">10</span><span class="pun">)</span><span class="pln">

plot_label </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">window</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"الرسم البياني"</span><span class="pun">,</span><span class="pln"> font</span><span class="pun">=(</span><span class="str">"tahoma"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">14</span><span class="pun">))</span><span class="pln">
plot_label</span><span class="pun">.</span><span class="pln">grid</span><span class="pun">(</span><span class="pln">row</span><span class="pun">=</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">=</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> columnspan</span><span class="pun">=</span><span class="lit">3</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"> pady</span><span class="pun">=</span><span class="lit">10</span><span class="pun">)</span><span class="pln">

window</span><span class="pun">.</span><span class="pln">mainloop</span><span class="pun">()</span></pre>

<p>
	توضح الصورة التالية نتيجة تنفيذ المشروع لحل معادلة درجة ثانية ورسم خطها البياني
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="139340" href="https://academy.hsoub.com/uploads/monthly_2023_12/469864998_.png.057bfa90e7fde5845cdc8a33e721e5ce.png" rel=""><img alt="مشروع حل معادلة" class="ipsImage ipsImage_thumbnailed" data-fileid="139340" data-ratio="78.50" data-unique="yx262ggxy" style="width: 600px; height: auto;" width="600" src="https://academy.hsoub.com/uploads/monthly_2023_12/.thumb.png.5e1a94e0496f27c459e9136a9a9c286c.png"> </a>
</p>

<p>
	<strong>توصيات حول المشروع:</strong>
</p>

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

<h3 id="-9">
	مشروع استخراج بيانات من موقع ويب
</h3>

<p>
	تعد مشاريع بايثون التي تقوم باستخراج البيانات من الويب Web Scraping من <a href="https://academy.hsoub.com/programming/python/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86/" rel="">تطبيقات بايثون</a> المفيدة والمطلوبة في سوق العمل فمن خلالها يمكنك جمع المعلومات المختلفة مثل أحدث الأخبار والمقالات، أو عناوين الكتب، أو المنشورات والتعليقات من مواقع التواصل، أو أسعار المنتجات من مواقع ويب بشكل تلقائي لسهولة تصفحها أو تنظيمها وتخزينها في ملفات قواعد بيانات ثم تحليلها ومقارنتها بدلاً من جلب هذه البيانات يدويًا من عدة أماكن.
</p>

<p>
	يمكنك بناء مشاريع بايثون Python لاستخراج بيانات الويب بسهولة بفضل ما توفره لغة بايثون من مكتبات مساعدة في هذا المجال مثل Beautiful Soup و Scrapy و Selenium لكن انتبه فبعض المواقع قد لا تسمح لك باستخراج البيانات منها وقد تحظر أي طلبات تقوم بها.
</p>

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

<p>
	سنقوم بإنشاء مشروع بلغة بايثون يستخرج أحدث المقالات المنشورة في موقع ووردبريس بالعربية باستخدام المكتبة tkinter و BeautifulSoup وهي مكتبة بايثون مشهورة تستخدم لتحليل مستندات HTML وXML واستخراج بياناتها والمكتبة requests لتقديم طلب HTTP GET إلى عنوان URL لصفحة الويب التي تريد استخراج بياناتها.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3507_32" style=""><span class="com"># مشروع استخلاص البيانات من موقع ووردبريس بالعربية</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><span class="kwd">from</span><span class="pln"> tkinter </span><span class="kwd">import</span><span class="pln"> ttk
</span><span class="kwd">from</span><span class="pln"> tkinter </span><span class="kwd">import</span><span class="pln"> scrolledtext  </span><span class="com"># لإضافة scrollbar للنتائج</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> requests
</span><span class="kwd">from</span><span class="pln"> bs4 </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">BeautifulSoup</span><span class="pln">

</span><span class="com"># استخلاص عناوين المقالات المنشورة حديثًا</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> fetch_and_extract_labels</span><span class="pun">():</span><span class="pln">
    url </span><span class="pun">=</span><span class="pln"> url_entry</span><span class="pun">.</span><span class="pln">get</span><span class="pun">()</span><span class="pln">

    result_text</span><span class="pun">.</span><span class="pln">config</span><span class="pun">(</span><span class="pln">state</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">NORMAL</span><span class="pun">)</span><span class="pln">
    result_text</span><span class="pun">.</span><span class="pln">delete</span><span class="pun">(</span><span class="lit">1.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">
    result_text</span><span class="pun">.</span><span class="pln">config</span><span class="pun">(</span><span class="pln">state</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">DISABLED</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
        response </span><span class="pun">=</span><span class="pln"> requests</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">url</span><span class="pun">)</span><span class="pln">
        response</span><span class="pun">.</span><span class="pln">raise_for_status</span><span class="pun">()</span><span class="pln">
        soup </span><span class="pun">=</span><span class="pln"> </span><span class="typ">BeautifulSoup</span><span class="pun">(</span><span class="pln">response</span><span class="pun">.</span><span class="pln">text</span><span class="pun">,</span><span class="pln"> </span><span class="str">'html.parser'</span><span class="pun">)</span><span class="pln">
        labels </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">link</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'aria-label'</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> link </span><span class="kwd">in</span><span class="pln"> soup</span><span class="pun">.</span><span class="pln">find_all</span><span class="pun">(</span><span class="str">'a'</span><span class="pun">,</span><span class="pln"> class_</span><span class="pun">=</span><span class="str">'p-flink'</span><span class="pun">)]</span><span class="pln">
        result_text</span><span class="pun">.</span><span class="pln">config</span><span class="pun">(</span><span class="pln">state</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">NORMAL</span><span class="pun">)</span><span class="pln">
        result_text</span><span class="pun">.</span><span class="pln">delete</span><span class="pun">(</span><span class="lit">1.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">

        result_text</span><span class="pun">.</span><span class="pln">tag_configure</span><span class="pun">(</span><span class="str">"rtl"</span><span class="pun">,</span><span class="pln"> justify</span><span class="pun">=</span><span class="str">"right"</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> label </span><span class="kwd">in</span><span class="pln"> labels</span><span class="pun">:</span><span class="pln">
            result_text</span><span class="pun">.</span><span class="pln">insert</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"> f</span><span class="str">"{label}\n"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"rtl"</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">except</span><span class="pln"> requests</span><span class="pun">.</span><span class="pln">exceptions</span><span class="pun">.</span><span class="typ">RequestException</span><span class="pln"> </span><span class="kwd">as</span><span class="pln"> e</span><span class="pun">:</span><span class="pln">
        result_text</span><span class="pun">.</span><span class="pln">config</span><span class="pun">(</span><span class="pln">state</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">NORMAL</span><span class="pun">)</span><span class="pln">
        result_text</span><span class="pun">.</span><span class="pln">delete</span><span class="pun">(</span><span class="lit">1.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">
        result_text</span><span class="pun">.</span><span class="pln">insert</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="str">"خطأ قي جلب البيانات-تحقق من العنوان"</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">except</span><span class="pln"> </span><span class="typ">Exception</span><span class="pln"> </span><span class="kwd">as</span><span class="pln"> e</span><span class="pun">:</span><span class="pln">
        result_text</span><span class="pun">.</span><span class="pln">config</span><span class="pun">(</span><span class="pln">state</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">NORMAL</span><span class="pun">)</span><span class="pln">
        result_text</span><span class="pun">.</span><span class="pln">delete</span><span class="pun">(</span><span class="lit">1.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">
        result_text</span><span class="pun">.</span><span class="pln">insert</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"> f</span><span class="str">"خطأ: {str(e)}"</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">finally</span><span class="pun">:</span><span class="pln">
        result_text</span><span class="pun">.</span><span class="pln">config</span><span class="pun">(</span><span class="pln">state</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">DISABLED</span><span class="pun">)</span><span class="pln">

app </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">
app</span><span class="pun">.</span><span class="pln">title</span><span class="pun">(</span><span class="str">"استخلاص البيانات"</span><span class="pun">)</span><span class="pln">

button_style </span><span class="pun">=</span><span class="pln"> ttk</span><span class="pun">.</span><span class="typ">Style</span><span class="pun">()</span><span class="pln">
button_style</span><span class="pun">.</span><span class="pln">configure</span><span class="pun">(</span><span class="str">"TButton"</span><span class="pun">,</span><span class="pln"> font</span><span class="pun">=</span><span class="str">"tahoma"</span><span class="pun">,</span><span class="pln"> padding</span><span class="pun">=</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> background</span><span class="pun">=</span><span class="str">"#3498db"</span><span class="pun">)</span><span class="pln">

url_label </span><span class="pun">=</span><span class="pln"> ttk</span><span class="pun">.</span><span class="typ">Label</span><span class="pun">(</span><span class="pln">app</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"عنوان الموقع"</span><span class="pun">,</span><span class="pln"> font</span><span class="pun">=</span><span class="str">"tahoma"</span><span class="pun">)</span><span class="pln">
url_label</span><span class="pun">.</span><span class="pln">pack</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">

default_url </span><span class="pun">=</span><span class="pln"> </span><span class="str">"https://www.wpar.net/"</span><span class="pln">
url_entry </span><span class="pun">=</span><span class="pln"> ttk</span><span class="pun">.</span><span class="typ">Entry</span><span class="pun">(</span><span class="pln">app</span><span class="pun">,</span><span class="pln"> width</span><span class="pun">=</span><span class="lit">50</span><span class="pln"> </span><span class="pun">,</span><span class="pln"> font</span><span class="pun">=</span><span class="str">"tahoma"</span><span class="pun">)</span><span class="pln">
url_entry</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="pln"> default_url</span><span class="pun">)</span><span class="pln">
url_entry</span><span class="pun">.</span><span class="pln">pack</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">

scrape_button </span><span class="pun">=</span><span class="pln"> ttk</span><span class="pun">.</span><span class="typ">Button</span><span class="pun">(</span><span class="pln">app</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"استخراج"</span><span class="pun">,</span><span class="pln"> style</span><span class="pun">=</span><span class="str">"TButton"</span><span class="pun">,</span><span class="pln"> command</span><span class="pun">=</span><span class="pln">fetch_and_extract_labels</span><span class="pun">)</span><span class="pln">
scrape_button</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">pady</span><span class="pun">=</span><span class="lit">10</span><span class="pun">)</span><span class="pln">

result_text </span><span class="pun">=</span><span class="pln"> scrolledtext</span><span class="pun">.</span><span class="typ">ScrolledText</span><span class="pun">(</span><span class="pln">app</span><span class="pun">,</span><span class="pln"> wrap</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">WORD</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">=</span><span class="lit">15</span><span class="pun">,</span><span class="pln"> width</span><span class="pun">=</span><span class="lit">50</span><span class="pun">,</span><span class="pln">font</span><span class="pun">=</span><span class="str">"tahoma"</span><span class="pun">)</span><span class="pln">
result_text</span><span class="pun">.</span><span class="pln">pack</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">
result_text</span><span class="pun">.</span><span class="pln">config</span><span class="pun">(</span><span class="pln">state</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">DISABLED</span><span class="pun">)</span><span class="pln">

app</span><span class="pun">.</span><span class="pln">mainloop</span><span class="pun">()</span></pre>

<p>
	عند تنفيذ المشروع والنقر على زر استخراج ستحصل على البيانات المطلوبة بالشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="PNG" data-fileid="139341" href="https://academy.hsoub.com/uploads/monthly_2023_12/---.PNG.d787feb5bc3aae1df3d125797cca3912.PNG" rel=""><img alt="مشروع استخلاص بيانات الويب" class="ipsImage ipsImage_thumbnailed" data-fileid="139341" data-ratio="96.18" data-unique="nhugvx7xc" style="width: 550px; height: auto;" width="550" src="https://academy.hsoub.com/uploads/monthly_2023_12/---.thumb.PNG.d1e8bd0508369d938855937543802396.PNG"> </a>
</p>

<p>
	<strong>توصيات حول المشروع:</strong>
</p>

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

<h2 id="-10">
	أفكار مشاريع بايثون أخرى للتدريب
</h2>

<p>
	استعرضنا لك في الفقرات السابقة عدة مشاريع بايثون جاهزة للمبتدئين والتي يمكنك تجربتها كمبتدئ وهناك بالطبع الكثير من أفكار شاريع بايثون للتدريب يمكنك تطبيقها فمجالات و<a href="https://academy.hsoub.com/programming/python/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86/" rel="">تطبيقات لغة بايثون</a> كثيرة ومتنوعة وإذا كنت مهتمًا بأحد هذه المجالات فمن الأفضل أن تركز على تطوير مشاريع فيه.
</p>

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

<ul>
	<li>
		مشروع يطلب من المستخدم إدخال تاريخ ميلاده ويحسب عمره بالأيام أو الأشهر أو السنوات.
	</li>
	<li>
		مشروع التحويل بين العملات.
	</li>
	<li>
		مشروع لعبة بسيطة مثل لعبة Tic-Tac-Toe أو لعبة مسابقات تطرح الأسئلة وتتحقق من الإجابات.
	</li>
	<li>
		مشروع توليد رمز QR للروابط.
	</li>
	<li>
		مشروع لتلخيص النصوص.
	</li>
	<li>
		مشروع فهرس أو قاموس بلغة بايثون.
	</li>
	<li>
		استخراج النص من مقطع فيديو.
	</li>
	<li>
		مشروع أتمتة مهام مثل مهمة التقاط الشاشة أو إرسال بريد إلكتروني.
	</li>
	<li>
		مشروع قواعد بيانات لحفظ أسماء جهات اتصالك وأرقامهم وعناوينهم.
	</li>
	<li>
		مشروع قائمة المهام.
	</li>
	<li>
		مشروع التحقق من صحة البريد الإلكتروني.
	</li>
	<li>
		مشروع استخراج أسماء وأسعار المنتجات من مواقع للتجارة الإلكترونية.
	</li>
	<li>
		مشاريع ذكاء اصطناعي بلغة البايثون مثل مشروع تصنيف الصور أو مشروع تصنيف رسائل البريد الإلكتروني.
	</li>
	<li>
		مشاريع بايثون للويب مثل <a href="https://academy.hsoub.com/programming/python/django/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%85%D9%87%D8%A7%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-%D9%88%D8%B1%D9%8A%D8%A2%D9%83%D8%AA-react-r1773/" rel="">تطبيق إدارة المهام To-do List</a> أو صفحة ويب بسيطة تعرض أعمالك.
	</li>
</ul>

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

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

<p>
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="450" id="ips_uid_7033_7" src="https://academy.hsoub.com/applications/core/interface/index.html" title="دورة تطوير التطبيقات بلغة بايثون - أكاديمية حسوب" width="800" data-embed-src="https://www.youtube.com/embed/1niwEWY7CN4"></iframe>
</p>

<h2 id="-11">
	الخلاصة
</h2>

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

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

<h2 id="-12">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D8%AA%D8%B9%D9%84%D9%85-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A3%D9%83%D9%88%D8%A7%D8%AF-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D9%85%D9%86-%D8%AE%D9%84%D8%A7%D9%84-%D8%A7%D9%84%D8%A3%D9%85%D8%AB%D9%84%D8%A9-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A%D8%A9-r2048/" rel="">تعلم كتابة أكواد بايثون من خلال الأمثلة العملية</a>
	</li>
	<li>
		<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="">مقدمة إلى دوال التعامل مع السلاسل النصية في بايثون 3</a>
	</li>
	<li>
		<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>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%AF%D9%88%D8%A7%D9%84-%D9%81%D8%B9%D8%A7%D9%84%D8%A9-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r2011/" rel="">كتابة دوال فعالة في بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D8%A8%D9%86%D8%A7%D8%A1-%D9%84%D8%B9%D8%A8%D8%A9-%D9%86%D8%B1%D8%AF-%D8%A8%D8%B3%D9%8A%D8%B7%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1703/" rel="">بناء لعبة نرد بسيطة بلغة بايثون</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2185</guid><pubDate>Mon, 04 Dec 2023 11:02:00 +0000</pubDate></item></channel></rss>
