عمليات التسلسلات في بايثون

من موسوعة حسوب

تدعم بايثون مجموعة من العمليات الخاصة بالتسلسلات (القوائم، والصفوف، وكائنات range، والسلاسل النصية، والبايتات ومصفوفات البايتات).

العمليات التي تدعمها معظم أنواع التسلسلات

يبين الجدول التالي مجموعة من العمليات المدعومة من قبل معظم أنواع التسلسلات بنوعيها القابل للتغيير (mutable) وغير القابل للتغيير (immutable).

في هذا الجدول يقصد بالحرفين s و t تسلسلين لهما النوع ذاته، وتمثّل الحروف n, i, j, k أعدادًا صحيحة، وتمثل x أي كائن تنطبق عليه القيود التي تفرضها قيم أو أنواع التسلسل s.

هذه العمليات مرتبة حسب أولويتها ترتيبًا تصاعديًا:

العملية النتيجة الملاحظات
x in s True إن كان عنصر من عناصر s يساوي x، وإلا False (1)
x not in s False إن كان عنصر من عناصر s يساوي x، وإلا True (1)
s + t ربط التسلسل s بالتسلسل t (6) (7)
s * n أو n * s تكافئ إضافة s إلى نفسه n مرة (2) (7)
s[i]‎ العنصر ذو الترتيب i في التسلسل s، يبدأ الترقيم من 0 (3)
s[i:j]‎ اقتطاع التسلسل s من العنصر i إلى العنصر j (3) (4)
s[i:j:k]‎ اقتطاع التسلسل s من العنصر i إلى العنصر j كل k خطوة (3) (5)
len(s)‎ طول التسلسل s
min(s)‎ أصغر عنصر في التسلسل s
max(s)‎ أكبر عنصر في التسلسل s
s.index(x[, i[, j]])‎ فهرس الظهور الأول للعنصر x في التسلسل s (عند أو بعد الفهرس i و قبل الفهرس j)

مثل الدالة str.index()‎.

(8)
s.count(x)‎ عدد مرات ظهور العنصر x في التسلسل s.

مثال: الدالة str.count()‎.

ملاحظات

1- صحيح أن عمليتي in و not in تستخدمان عادة للتحقق من وجود قيمة معينة ضمن عناصر التسلسل، ولكن بعض أنواع التسلسلات (السلاسل النصية، والبايتات ومصفوفات البايتات) تستخدم هذه العملية لاختبار السلاسل الفرعية:

>>> "gg" in "eggs"
True

2- تعامل قيم n التي تقل عن الصفر معاملة الصفر، وهذا يؤدي إلى إنشاء تسلسل فارغ من نفس نوع التسلسل s. لاحظ أنّ عناصر التسلسل s لن تنسخ وإنّما سيشار إليها عدّة مرات، وهنا يُخطئ الكثير من المبتدئين في لغة بايثون، فمثلًا:

>>> lists = [[]] * 3
>>> lists
[[], [], []]
>>> lists[0].append(3)
>>> lists
[[3], [3], [3]]

ما حدث هنا أنّ التعبير [[]] يمثّل قائمة ذات عنصر واحد هو بدوره قائمة فارغة؛ لذا تكون العناصر الثلاثة الناشئة من التعبير ‎[[]] * 3‎ إشارات إلى هذه القائمة الفارغة، ويؤدي تعديل أي عنصر من عناصر القوائم الثلاثة إلى تعديل القائمة الأولى. يمكن اتباع الطريقة التالية لإنشاء قائمة تتضمن قوائم مختلفة:

>>> lists = [[] for i in range(3)]
>>> lists[0].append(3)
>>> lists[1].append(5)
>>> lists[2].append(7)
>>> lists
[[3], [5], [7]]

3- إن كان العدد i أو j سالبًا، فإن عملية الفهرسة تجري من نهاية التسلسل s وتكون مكافئة للتعبير len(s) + i أو len(s) + j. لاحظ أنّ القيمة ‎-0 تساوي 0.

4- يعرّف الجزء المقتطع من التسلسل s والذي يبدأ من الموقع i إلى الموقع j على أنّه تسلسل العناصر ذات الفهرس k بحيث تكون ‎i <= k < j‎. إذا كانت قيمة i أو j أكبر من قيمة len(s)‎ تستخدم اللغة len(s)‎. إذا لم تعيّن قيمة i أو كانت None تستخدم اللغة القيمة 0. إذا لم تعيّن قيمة j أو كانت None تستخدم اللغة len(s)‎. إن كانت قيمة i أكبر من قيمة j أو تساويها فسيكون الجزء المقتطع فارغًا.

5- يعرّف الجزء المقتطع من التسلسل s والذي يبدأ بالموقع i وينتهي بالموقع j كل k خطوة على أنّه تسلسل العناصر الذي يمتلك الفهرس x = i + n*k بحيث ‎0 <= n < (j-i)/k. وبمعنى آخر، فإنّ الفهارس هي i، i+k، i+2*k، i+3*k وهكذا دواليك إلى حين الوصول إلى قيمة j (دون تضمين قيمة j). عندما تكون قيمة k موجبة تختزل قيمتا i و j إلى len(s)‎ إن كانتا أكبر. عندما تكون قيمة k سالبة، تختزل قيمتا i و j إلى len(s)‎ - 1 إن كانتا أكبر. إن لم تعين قيمة i أو j، أو كانت None فإنّهما يصبحان قيمة النهاية (والتي تعتمد على إشارة k). لاحظ أنّه لا يمكن أن تأخذ k القيمة 0. إن كانت قيمة k هي None فإنّ اللغة ستعدّها 1.

6- يؤدي ربط تسلسلات غير قابلة للتغيير إلى إنشاء كائنات جديدة دائمًا، وهذا يعني إن إنشاء تسلسل من عمليات ربط متعددة سيؤدي إلى استهلاك مضاعف للموارد في وقت التشغيل بالنسبة إلى الطول الكلي للتسلسل، ولجعل عملية الاستهلاك أقل وطأة يجب اختيار أحد البدائل التالية:

  • إن كانت عملية الربط تجري بين كائنات str فيمكن إنشاء قائمة واستخدام التابع str.join()‎ في النهاية أو الكتابة إلى نسخة io.StringIO ثم استعادة قيمته عند الانتهاء.
  • إن كانت عملية الربط تجري بين كائنات bytes فيمكن بنفس الطريقة استخدام bytes.join()‎ أو io.BytesIO، أو يمكن إجراء الربط في نفس المكان باستخدام كائن bytearray القابلة للتغيير.
  • إن كانت عملية الربط بين كائنات tuple فيمكن توسيع عناصر قائمة list بدلًا من ذلك.

7- تدعم بعض أنواع التسلسلات (مثل range) نمطًا معيّنًا من تسلسل العناصر؛ لذا فإنّها لا تدعم عمليات الربط والتكرار.

8- تطلق الدالة index()‎ خطأً من نوع ValueError عندما لا تعثر اللغة على x في التسلسل s. قد لا تدعم بعض طرق استخدام هذه العملية تمرير الوسائط الإضافية i و j. تساعد هذه الوسائط على إجراء عملية بحث فعّالة على أجزاء من التسلسل. يكافئ تمرير الوسائط الإضافية استخدام العبارة s[i:j].index(x)‎ باستثناء عدم نسخ أي بيانات وإعادة فهرس يبدأ من بداية التسلسل بدلًا من بداية الجزء المقتطع.

عمليات التسلسلات غير القابلة للتغيير

تقدّم بايثون عملية واحدة فقط خاصّة بالتسلسلات غير القابلة للتغيير، وهذه العملية هي الدالة الداخلية hash()، تتيح هذه العملية استخدام التسلسلات غير القابلة للتغيير مثل الصفوف كمفاتيح في القواميس وتخزينها في المجموعات أو المجموعات الجامدة.

تؤدي محاولة تقطيع hash تسلسل يتضمّن قيمًا غير قابلة للتقطيع إلى إطلاق خطأً من نوع TypeError.

عمليات التسلسلات القابلة للتغيير

تقدّم بايثون مجموعة من العمليات الخاصّة بالتسلسلات القابلة للتغيير، وهي موضّحة في الجدول التالي.

في هذا الجدول تمثّل s نسخة من تسلسل قابل للتغيير، وتمثّل t أي كائن يمكن المرور على عناصره (iterable) و تمثّل x كائنًا غير محدّد تنطبق عليه القيود التي تفرضها قيم أو أنواع التسلسل s (مثلًا: يتقبل النوع bytearray الأعداد الصحيحة المحصورة بالنطاق ‎0 <= x <= 255فقط).

العملية النتيجة الملاحظات
s[i] = x استبدال العنصر i التابع للتسلسل s بقيمة x
s[i:j] = t استبدال الجزء المقتطع من s من الموقع i إلى الموقع j بمحتويات الكائن t
del s[i:j]‎ مشابهة للتعبير s[i:j] = []‎
s[i:j:k] = t‎ استبدال العناصر الناتجة من s[i:j:k]‎بعناصر t يجب أن تمتلك t نفس طول التسلسل المقتطع المراد استبداله.
del s[i:j:k]‎ حذف العناصر الناتجة من s[i:j:k]‎ من القائمة
s.append(x)‎ إلحاق x بنهاية التلسلسل (مكافئ للتعبير s[len(s):len(s)] = [x]‎) مثل الدالة list.append()‎.
s.clear()‎ حذف جميع عناصر التسلسل s (مكافئ للتعبير del s[:]‎) توفّر بايثون هذه الدالة كبديل لعمليات التقطيع التي لا تدعمها بعض أنواع التسلسلات (مثل القواميس والمجموعات).

قدّم الإصدار 3.3 من اللغة هذه الدالة لأول مرة.

مثال: الدالة list.clear()‎.

s.copy()‎ إنشاء نسخة سطحية من s (مكافئ للتعبير s[:]‎) توفّر بايثون هذه الدالة كبديل لعمليات التقطيع التي لا تدعمها بعض أنواع التسلسلات (مثل القواميس والمجموعات).

قدّم الإصدار 3.3 من اللغة هذه الدالة لأول مرة.

مثال: الدالة list.copy()‎.

s.extend(t)‎ أو s += t‎ إضافة محتويات t إلى التسلسل s (مكافئ للتعبير s[len(s):len(s)] = t‎ في معظم الحالات) مثال الدالة: list.extend()‎.
s *= n تحديث قيمة s مع تكرار عناصره n مرة يمثل n عددًا صحيحًا، أو كائنًا يستخدم التابع ‎__index__()‎. يؤدي استخدام القيمة 0 أو أي قيمة سالبة إلى إفراغ التسلسل من محتوياته. لن تُنسخ عناصر التسلسل بل سيشار إليها لمرات عدة، وكما هو موضح في العملية s * n في أعلاه.
s.insert(i, x)‎ إدراج x في التسلسل s في الموقع i (مكافئ للتعبير s[i:i] = x). مثال: الدالة list.insert()‎.
s.pop([i])‎ إعادة العنصر i وحذفه من التسلسل. يأخذ الوسيط الاختياري i القيمة الافتراضية ‎-1؛ لذا تعيد هذه الدالة العنصر الأخير وتحذفه بصورة افتراضية.

مثال: الدالة list.pop()‎.

s.remove(x)‎ حذف أول عنصر في التسلسل s حيث s[i] == x تطلق هذه الدالة خطأً من نوع ValueError عندما لا يكون x موجودًا في s.

مثال: الدالة list.remove()‎.

s.reverse()‎ قلب عناصر التسلسل s ضمن التسلسل نفسه. تقلب هذه الدالة التسلسل في مكانه وذلك اقتصادًا في الموارد عند قلب عناصر تسلسل كبير الحجم. لا تعيد هذه الدالة التسلسل المقلوب.

مثال: الدالة list.reverse()‎.

مصادر