القوائم في بايثون: تسلسل مرتّب وقابل للتعديل
تُعدّ القوائم (list) من أكثر أنواع المجموعات استخدامًا في بايثون على الإطلاق. فإذا كنت تحتفظ بمجموعة مرتّبة من القيم قابلة للتغيير — سواء بالإضافة أو الحذف أو الترتيب أو التحديث — فإن الـ list هي الخيار الأنسب في معظم الحالات.
تكتب القوائم في بايثون بين قوسين مربعين هكذا:
القوائم في بايثون قادرة على تخزين أي شيء، حتى قوائم أخرى. لكن عملياً، أغلب القوائم اللي بتشتغل عليها راح تحتوي على نوع واحد من العناصر — قائمة مستخدمين، أو قائمة أرقام — لأن هذا الأسلوب أسهل في الفهم والتعامل.
الوصول إلى عناصر القائمة عبر الفهرسة (Indexing)
كل عنصر داخل القائمة له موقع (index) يبدأ من الصفر، وتقدر توصل لأي عنصر عن طريق الأقواس المربعة:
عند محاولة الوصول إلى فهرس غير موجود، تحصل على IndexError. لذلك إذا كنت غير متأكد من وجود العنصر، يُفضّل أن تتحقق من طول القائمة أولاً أو تضع عملية الوصول داخل try.
التقطيع (Slicing) في قوائم بايثون
يتيح لك التقطيع الحصول على نطاق من العناصر دفعة واحدة. الصياغة هي list[start:stop:step]، وهي نفس الصياغة المستخدمة مع النصوص:
نقطتان مهمتان لازم تثبتهم في ذهنك:
list slicingفي بايثون دائماً يُرجِع قائمة جديدة. أي تعديل على الشريحة لن يمس القائمة الأصلية.- فهرس النهاية غير مشمول — يعني
nums[2:5]يعطيك العناصر في المواضع 2 و 3 و 4 فقط، وليس 5.
إضافة عنصر إلى قائمة بايثون باستخدام append و extend و insert
الدوال الثلاث المستخدمة لإضافة العناصر إلى القائمة تعمل بطرق مختلفة تماماً، والخلط بينها من أكثر أسباب الأخطاء شيوعاً:
append(x): يُضيفxكعنصر واحد فقط، حتى لو كانxعبارة عن قائمة. مثلاًitems.append([1, 2])ستضيف القائمة نفسها كعنصر واحد داخل القائمة.extend(iterable): يُضيف كل عنصر من عناصر الـ iterable على حدة. فمثلاًitems.extend([1, 2])ستضيف عنصرين.insert(i, x): يُدرج العنصر عند فهرس محدّد، مع إزاحة كل ما يقع عند الفهرسiأو بعده بمقدار موضع واحد.
استخدام += مع قائمة يعمل تماماً مثل extend:
وأمّا للحذف:
إذا حاولت استخدام remove() مع عنصر غير موجود في القائمة، سيرفع بايثون استثناء ValueError. لو كنت تريد منطق "احذفه إن وُجد"، فتحقّق أولًا باستخدام in، أو استخدم try.
كما يمكنك حذف عنصر من قائمة بايثون عن طريق رقم الفهرس مباشرةً باستخدام del:
الطول، الانتماء، والعد
in هي الطريقة الأوضح للتحقق من وجود قيمة داخل القائمة. لكن إذا كنت ستكرر هذا السؤال مرات كثيرة على قائمة كبيرة، استخدم set بدلاً من ذلك — فالبحث في set يكون بتعقيد O(1)، بينما البحث في القائمة يكون O(n).
ترتيب قائمة في بايثون
في طريقتان، والفرق بينهما مهم:
كِلاهما يقبل الوسيط reverse=True للترتيب التنازلي:
ومعامل key للترتيب المُخصَّص:
يُطبَّق key على كل عنصر، والنتيجة هي ما تتم المقارنة عليه. من أكثر الاستخدامات شيوعًا: الترتيب حسب الطول، أو حسب خاصية معينة، أو حسب صيغة الأحرف الصغيرة للنص.
عكس قائمة بايثون
هناك ثلاث طرق، ويعتمد اختيارك على ما تحتاجه فعلًا:
استخدم التعديل في المكان (in-place) عندما لا تحتاج إلى القائمة الأصلية. استخدم الـ slicing لما تبغى نسخة جديدة. استخدم reversed() إذا كنت فقط تريد المرور على العناصر بترتيب معكوس دون إنشاء قائمة جديدة فعليًا.
فخ المرجع المشترك في قوائم بايثون
القوائم في بايثون قابلة للتعديل (mutable)، والمتغيرات ما هي إلا مراجع (references). معنى هذا أن متغيرَين قد يشيران إلى نفس القائمة:
b = a لم ينسخ القائمة، بل جعل b مجرد اسم آخر لنفس القائمة. وإذا أردت نسخة فعلية، فاطلبها صراحةً:
هذي النقطة تلدغ كل مبرمج بايثون مرة على الأقل في حياته. خلّيها ببالك دائماً: علامة = بين قائمتين ما تنسخ القائمة.
المرور على القوائم وبناؤها
النمط الأساسي صار معروفاً لديك من درس حلقة for:
هذا الأسلوب واضح ومفهوم، ولن يسبب لك أي مشكلة. وعندما تشعر بالارتياح في التعامل مع القوائم في بايثون، يمكنك استخدام الـ list comprehension الذي ينجز نفس المهمة في سطر واحد:
سنتناول الـ comprehensions بالتفصيل بعد صفحتين من الآن.
ورقة مرجعية سريعة
أهم التوابع التي يجدر بك معرفتها باختصار:
append(x)— إضافة عنصر إلى نهاية القائمةextend(iter)— إضافة كل عناصر كائن قابل للتكرارinsert(i, x)— إدراج عنصر عند الموضع ipop()/pop(i)— حذف عنصر وإرجاعهremove(x)— حذف أول ظهور للعنصر xsort()/sort(key=...)/sort(reverse=True)— ترتيب قائمة في بايثونreverse()— عكس قائمة بايثونindex(x)— موضع أول ظهور لـ xcount(x)— عدد مرات تكرار xcopy()— نسخة سطحية (shallow copy)
ماذا بعد؟
القوائم في بايثون هي حصان العمل الذي ستعتمد عليه كثيراً. في الدرس التالي سنتعرّف على الـ tuples — القريبة غير القابلة للتعديل من القوائم — ومتى يكون اللجوء إلى tuple بدلاً من list هو الخيار الأنسب.
الأسئلة الشائعة
كيف أنشئ قائمة في بايثون؟
استخدم الأقواس المربعة مع قيم مفصولة بفواصل، هكذا: fruits = ['apple', 'banana', 'cherry']. القائمة في بايثون تقبل أي نوع من البيانات، ويمكنك خلط الأنواع داخلها، لكن في الغالب يُفضّل المبرمجون أن تكون عناصر القائمة من نفس النوع لسهولة التعامل معها.
كيف أرتّب قائمة في بايثون؟
استدعِ .sort() على القائمة لترتيبها في مكانها مباشرة، أو استخدم الدالة المدمجة sorted(list) للحصول على قائمة جديدة مرتبة دون المساس بالأصلية. كلا الطريقتين تدعم المعامل reverse=True للترتيب التنازلي، والمعامل key= لتحديد مفتاح ترتيب مخصّص.
كيف أعكس قائمة في بايثون؟
list.reverse() يعكس القائمة في مكانها. بينما list[::-1] يُرجع نسخة جديدة معكوسة. أما reversed(list) فيُعيد مُكرِّرًا (iterator) يمكنك المرور عليه في حلقة. اختر ما يناسب حالتك: تعديل في المكان، أو نسخة جديدة، أو تكرار كسول.