في Python ، هناك نوعان متشابهان - list (list) و tuple (tuple). الاختلاف الأكثر شهرة بين الاثنين هو أن الصفوف غير قابلة للتغيير.
لا يمكنك تغيير الكائنات في مجموعة:
>>> a = (1,2,3) >>> a[0] = 10 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'tuple' object does not support item assignment
ولكن يمكنك تعديل كائنات قابلة للتغيير داخل مجموعة tuple:
>>> b = (1,[1,2,3],3) >>> b[1] [1, 2, 3] >>> b[1].append(4) >>> b (1, [1, 2, 3, 4], 3)
داخل CPython (المترجم المعياري) ، يتم تنفيذ القائمة والمجموعة في شكل ورقة من المؤشرات (روابط) إلى كائنات Python ، أي جسديًا لا يخزنون أشياء بجوار بعضهم البعض. عند حذف كائن من القائمة ، يتم حذف المرجع إلى هذا الكائن. إذا أشار شخص آخر إلى الكائن ، فسيظل في الذاكرة.
Tuples
على الرغم من حقيقة أن الصفوف أقل شيوعًا في التعليمات البرمجية وليست شائعة جدًا ، إلا أن هذا النوع أساسي جدًا يستخدمه Python باستمرار للأغراض الداخلية.
قد لا تلاحظ ، ولكنك تستخدم الصفوف عندما:
- العمل مع الحجج أو المعلمات (يتم تخزينها على شكل صفوف)
- إرجاع متغيرين أو أكثر من دالة
- كرر مفاتيح القيمة في القاموس
- استخدام تنسيق السلسلة
عادةً ما يستخدم أبسط نص برمجي آلاف الصفوف:
>>> import gc >>> def type_stats(type_obj): ... count = 0 ... for obj in gc.get_objects(): ... if type(obj) == type_obj: ... count += 1 ... return count ... >>> type_stats(tuple) 3136 >>> type_stats(list) 659 >>> import pandas >>> type_stats(tuple) 6953 >>> type_stats(list) 2455
القوائم الفارغة مقابل الصفوف الفارغة
تعمل المجموعة الفارغة مثل المفرد ، أي هناك دائمًا مجموعة فارغة واحدة فقط في ذاكرة نص Python الجاري تشغيله. تشير جميع الصفوف الفارغة ببساطة إلى نفس الشيء ، وهذا ممكن لأن الصفوف غير قابلة للتغيير. هذا النهج يوفر الكثير من الذاكرة ويسرع عملية العمل مع الصفوف الفارغة.
>>> a = () >>> b = () >>> a is b True >>> id(a) 4409020488 >>> id(b) 4409020488 >>>
لكن هذا لا يعمل مع القوائم ، لأنه يمكن تغييرها:
>>> a = [] >>> b = [] >>> a is b False >>> id(a) 4465566920 >>> id(b) 4465370632
تحسين تخصيص الذاكرة للصفوف
من أجل تقليل تجزئة الذاكرة وتسريع إنشاء الصفوف ، يعيد Python استخدام الصفوف القديمة التي تم حذفها. إذا كان الصف يحتوي على أقل من 20 عنصرًا ولم يعد مستخدمًا ، فبدلاً من حذفه ، تضعه Python في قائمة خاصة ، والتي تخزن الصفوف مجانًا لإعادة استخدامها.
تنقسم هذه القائمة إلى 20 مجموعة ، حيث تكون كل مجموعة قائمة من الصفوف ذات الحجم n ، حيث تكون n من 0 إلى 20. يمكن لكل مجموعة تخزين ما يصل إلى 2000 صف مجاني. تقوم المجموعة الأولى بتخزين عنصر واحد فقط وهي قائمة لمجموعة واحدة فارغة.
>>> a = (1,2,3) >>> id(a) 4427578104 >>> del a >>> b = (1,2,4) >>> id(b) 4427578104
في المثال أعلاه ، يمكننا أن نرى أن a و b لهما نفس العنوان في الذاكرة. هذا يرجع إلى حقيقة أننا أخذنا على الفور tuple مجاني من نفس الحجم.
تحسين تخصيص الذاكرة للقوائم
نظرًا لأن القوائم عرضة للتغيير ، لم يعد من الممكن تطبيق التحسين نفسه كما هو الحال في حالة الصفوف. على الرغم من ذلك ، تستخدم القوائم تحسينات مماثلة تستهدف القوائم الفارغة. إذا تم حذف القائمة الفارغة ، فيمكن أيضًا إعادة استخدامها في المستقبل.
>>> a = [] >>> id(a) 4465566792 >>> del a >>> b = [] >>> id(b) 4465566792
قائمة تغيير الحجم
لتجنب عبء تغيير حجم القوائم باستمرار ، لا تقوم Python بتغيير حجمها في كل مرة تكون مطلوبة. بدلاً من ذلك ، تحتوي كل قائمة على مجموعة من الخلايا الإضافية المخفية للمستخدم ، ولكن يمكن استخدامها لاحقًا للعناصر الجديدة. بمجرد انتهاء الخلايا المخفية ، يضيف Python مساحة إضافية للعناصر الجديدة. وهو يفعل ذلك بهامش جيد ، يتم تحديد عدد الخلايا المخفية بناءً على الحجم الحالي للقائمة - كلما كان أكبر ، كلما كانت الخانات الإضافية الإضافية للعناصر الجديدة أكبر.
هذا التحسين مفيد بشكل خاص عندما تحاول إضافة العديد من العناصر في حلقة.
يبدو نمط نمو حجم القائمة كالتالي: 0 ، 4 ، 8 ، 16 ، 25 ، 35 ، 46 ، 58 ، 72 ، 88 ، ...
على سبيل المثال ، إذا كنت ترغب في إضافة عنصر جديد إلى قائمة تحتوي على 8 عناصر ، فلن تكون هناك خلايا مجانية فيه وسيقوم Python على الفور بتوسيع حجمه إلى 16 خلية ، حيث سيتم شغل 9 منها وتكون مرئية للمستخدم.
صيغة بايثون التحجيم:
>>> def get_new_size(n_items): ... new_size = n_items + (n_items // 2 ** 3) ... if n_items < 9: ... new_size += 3 ... else: ... new_size += 6 ... ... return new_size ... >>> get_new_size(9) 16
السرعة
إذا قارنا هذين النوعين من السرعة ، ففي المتوسط في المستشفى ، تكون الصفوف أسرع قليلاً من القوائم. يقدم Raymond Hettinger شرحًا رائعًا لاختلاف السرعة في
تدفق المكدس .
ملاحظة: أنا مؤلف هذا المقال ، يمكنك طرح أي أسئلة.