PyDA Course
📖 درس 15 مبتدئ ⏱ 18 دقيقة ⚡ +10 XP ColabKagglenbviewerBinderDeepnoteGitHub list · tuple · sequence · mutable · immutable

القوائم والجداول (Lists and Tuples)

خزّن المتتاليات واستكشف توماس الغوص في القوائم والجداول.

🎯 ماذا ستتعلم:
  • إنشاء القوائم والوصول إلى عناصرها وتعديلها
  • استخدام الجداول كمتتاليات غير قابلة للتعديل
  • اختيار بين القوائم والجداول
  • نسخ التسلسلات دون المشاركة المريبة لمراجع الكائنات

المتتالية المرتّبة القابلة للتعديل

القائمةُ تسلسلٌ تستطيع تنميته وتقليصه وإعادة ترتيبه. والوصولُ يطيع كلَّ ما علّمك إياه التقسيم:

python
fruits = ["apple", "banana", "cherry"]
print(fruits[0])       # apple
print(fruits[-1])      # cherry
print(fruits[0:2])     # ['apple', 'banana']

الفهرسةُ من صفرٍ، والمؤشراتُ السالبةُ العدَّ عكسيًّا، والشرائحُ آخذةً نوافذَ ، المهاراتُ الثلاثُ نفسُها، موجّهةً الآن إلى مجموعةِ أيِّ كائناتٍ. وحيث كانت السلسلةُ مجمَّدةً، كانت القائمةُ طينًا.

عدةُ القائمة

الطرقُ ورشةُ تعديلاتٍ:

python
nums = [3, 1, 4, 1, 5]
nums.append(9)       # [3, 1, 4, 1, 5, 9]
nums.insert(0, 0)    # [0, 3, 1, 4, 1, 5, 9]
nums.extend([2, 6])  # [0, 3, 1, 4, 1, 5, 9, 2, 6]
nums.pop()           # يزيل 9 ويرجعه
nums.remove(1)       # يزيل أول 1
nums.sort()          # يرتّب في موضعه
nums.reverse()       # يعكس في موضعه
len(nums)            # الطول الحالي

يضيف append عنصرًا واحدًا في النهاية؛ ويصبّ extend تسلسلًا كاملًا؛ ويُنزلق insert عنصرًا في مركزٍ مختارٍ. يزيل pop من النهاية (أو من مركزٍ معيّنٍ) ويُسلّمك القيمةَ المزالة؛ ويمحو remove أولَ عنصرٍ مطابقٍ. وإنّ القائمةَ لابنُ العمِّ القابلُ للتغييرِ لخيولِ عملٍ كامتدادِ أرقامِ π\pi ، خيطُ قيمٍ متنامٍ ظللتَ تحرّره.

قوائم داخل قوائم: جداول ومصفوفات

يمكن أن تكون عناصرُ القائمةِ قوائمَ بدورها، ما يحوّل تسلسلًا مسطحًا إلى جدول ، المصفوفةُ قائمةٌ من الصفوف، وكلُّ صفٍّ قائمةُ أعدادٍ:

python
matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
]
print(matrix[1][2])     # 6  — الصف 1، العمود 2
print(matrix[1])        # [4, 5, 6]

يختار matrix[1] الصفَّ الثاني؛ وإضافةُ [2] تنزل إلى ذلك الصفِّ وتختار عنصرَه الثالث. يُخاطب العنوانانِ خليةً تمامًا كما يسمّي العددُ السفليُّ M1,2M_{1,2} مدخلًا في مصفوفةٍ على الورق. الحيلةُ نفسُها تبني شبكاتٍ ولوحاتِ ألعابٍ وصفوفَ جداولِ بياناتٍ.

الطفرة مقابل قائمةٍ جديدة: شوكةٌ تعض

هنا خللٌ يكدّم المبتدئين. بعضُ الطرق تُحدِث طفرةً في القائمة وترجع None؛ وبعضُها يرجع قائمةً جديدةً ويترك الأصلَ سليمًا. وصوتُ الطريقة لا يخبرك بأيةٍ هما:

python
nums = [3, 1, 2]
result = nums.sort()   # result هو None! nums الآن [1, 2, 3]
result = sorted(nums)  # result هو [1, 2, 3]، nums لم تتغير

يرتّب nums.sort() في موضعٍ ولا يرجع شيئًا ، قيمةُ تعبيرك هي None. بينما يحسب sorted(nums) قائمةً جديدةً مرتّبةً ويترك nums كما هي. والاسمُ هو الإشارة: أفعالٌ كـ sort وreverse تلمس الكائنَ؛ وsorted وlist.copy() ترسمان نسخةً لمالكٍ جديد.

الجداول: المتتالية المجمَّدة

الجَدْوِلُ متتاليةٌ مرتّبةٌ غيرُ قابلةٍ للتعديل ، قائمةٌ فقدت أداةَ تحريرها:

python
point = (3, 4)
print(point[0])   # 3
# point[0] = 5   # TypeError!

عدمُ القابليةِ للتعديل ليس عجزًا؛ إنه وعدٌ. النقطةُ (3,4)(3, 4) كائنٌ رياضيٌّ واحدٌ لا ينبغي أن يتغير تحت قدميك. الإحداثياتُ، وألوانُ RGB، وصفوفُ قواعدِ البيانات ، البياناتُ الثابتةُ بالتعريف تخصّ الجداول، حيث يصبح إسنادُ العَرَضِ استثناءً لا فسادًا صامتًا.

التفكيك: سطرٌ واحدٌ بأسماءٍ كثيرة

يستطيع تسلسلٌ أن يطويَ نفسَه في متغيراتٍ متعددةٍ في إسنادٍ واحدٍ. وتجمع بايثون حتى الفائضَ باسمٍ بنجمٍ:

python
x, y = (3, 4)         # x=3, y=4
a, b, *rest = [1, 2, 3, 4, 5]  # a=1, b=2, rest=[3, 4, 5]
first, *_, last = (1, 2, 3, 4)  # first=1, last=4

يبتلع *rest كلَّ ما بين الشقوق المسمّاة؛ و*_ نفسُ الإيماءةِ تحمل اسمَ «تجاهل هذا» المعهودَ. إنها نسخةُ القائمةِ من تقييم دالةٍ عند نقطةٍ ، مدخلاتٌ ومخرجاتٌ تناصفٌ وفقًا للموقع.

مثالٌ محلول: دفترُ الدرجات

شاهدِ الأدواتِ تعمل في مهمةٍ واقعية ، درجاتُ الصفِّ في اختبارٍ:

python
scores = []
scores.append(8)
scores.append(6)
scores.extend([9, 7, 10])

total = sum(scores)       # sum() تجمع كل عنصر
best = max(scores)        # max() تجد الأكبر
count = len(scores)       # len() تعدّها
average = total / count

print(average)            # 8.0
print(best)               # 10

اجمع بـ append/extend ثم اقرأ بـ sum وmax وlen. لاحظِ القسمةَ: total / count هي المتوسطُ الحسابي ، وهو نفسُ المجموعالعدد\frac{\text{المجموع}}{\text{العدد}} الذي تعرفه من الرياضيات، الآن في سطرٍ واحد. القائمةُ مكانٌ لتجميعِ البيانات، والدورةُ بين إشباعِها وقراءتِها هي النمطُ الذي يكرّره كلُّ برنامجٍ حقيقيٍّ.

أخطاء شائعة

  • sort() يرجع None. إذا أردت قائمةً جديدةً، فدَع sorted() يحمل القيمةَ.
  • خلطُ النسخِ السطحي. يصنع a = b اسمينِ لقائمةٍ واحدةٍ؛ أما a = b.copy() أو a = list(b) فيبنيان قائمةً منفصلةً.
  • مزج الأنواع. [1, "two", 3.0] مشروعٌ لكنه يُعسّر المقارناتِ والاستدلال؛ أبْقِ المجموعاتِ صادقةً على محتوياتها.
  • append مقابل extend. يجعل nums.append([1, 2]) قائمةً متداخلةً عنصرًا واحدًا؛ بينما يُفرّغ nums.extend([1, 2]) عناصرها عناصرَ منفصلةً.
  • يحذف remove أولَ تطابقٍ فقط. يترك [1, 2, 1].remove(1) القائمةَ [2, 1]؛ ويمسحُ النسخَ كلَّها حلقةٌ (درسٌ لاحق).

🧩 تحديات

🧩 تحدٍّ ، فكّر أولًا ثم أظهر

احذف التكرارات محافظًا على الترتيب: [1, 3, 2, 3, 1, 4, 2][1, 3, 2, 4].

💡 الجواب: list(dict.fromkeys(nums)) ، يحفظ القاموسُ ترتيبَ الإدراج (منذ 3.7)، وتنطوي المفاتيحُ المكررةُ إلى موضعها الأول.

🧩 تحدٍّ ، فكّر أولًا ثم أظهر

بادل بين متغيرينِ دون متغيرٍ مؤقتٍ، مستخدمًا تفكيكَ الجداول.

💡 الجواب: a, b = b, a ، يُقيَّم الطرفُ الأيمنُ جدولًا أولًا، فالمبادلةُ آنيةٌ لا تتابعيةٌ.

🤔 أسئلة سقراطية

  • متى تلجأ إلى جَدْوِلٍ دون قائمةٍ، وماذا تشتري لك عدمُ القابليةِ للتعديل؟
  • لماذا يُحدِث sort() طفرةً حيث يرجع sorted() جديدًا ، ومتى تفضّل كلًّا؟
  • كيف يجمع *rest الفائضَ؟ وهل يقدر *_ على نيابةِ تجاهلٍ مسموٍّ؟

✅ فحص سريع

١. ماذا يطبع هذا؟ a = [1, 2]; b = a; b.append(3); print(a)؟

٢. أيهما صحيح؟ a, b, c = [1, 2]

listtuplesequencemutableimmutable