المستوى: محترف
لو سيرفر Python عندك بيخزّن ملايين الـ instances في الذاكرة وبتدفع لـ AWS أكتر من اللازم في الـ RAM، فيه سطر واحد ممكن يقلّل استهلاك الذاكرة لكل instance بنسبة 40 إلى 60 بالمية. السطر ده اسمه __slots__، وأغلب مطوري Python بيتجاهلوه لأنهم مش فاهمين ليه الكلاس العادي بياكل ذاكرة كده من الأساس.
__slots__ في Python: التحسين اللي بيغيّر اقتصاديات السيرفر
المشكلة باختصار
كل instance بتنشئه من class عادي في Python بيجي معاه dictionary مخفي اسمه __dict__. الـ dictionary ده مسؤول عن تخزين الـ attributes بتاعت الـ object، وبيدّيك مرونة كاملة تضيف attributes جديدة في أي وقت. لكن المرونة دي ليها تكلفة: كل __dict__ بياخد حوالي 232 byte حتى لو الـ instance فيه 3 attributes بس. لو عندك مليون instance، ده 232 ميجابايت RAM ضايعة على بنية بيانات أنت أصلًا مش محتاج مرونتها.
المثال البسيط: درج المكتب
تخيل إن عندك مكتبين شغل. المكتب الأول درج كبير وفاضي وانت بترمي فيه أي حاجة - مفاتيح، ورق، قلم، أي شيء جديد - والدرج بيتمدد علشان يستوعب أي إضافة. المكتب التاني فيه 3 خانات صغيرة مقسومة سلفًا: واحدة للمفاتيح، واحدة للورق، واحدة للقلم. خلاص. مفيش مكان لحاجة رابعة.
المكتب الأول هو الـ __dict__ الافتراضي اللي بيجي مع كل class. المكتب التاني هو __slots__. المرونة بتنقص، لكن المساحة اللي بتاخدها أقل بكتير لأن مفيش buffer مخصص لاحتمالات مستقبلية مش هتحصل.
الشرح العلمي الدقيق
لما بتعرّف class عادي، Python بينشئ لكل instance attribute lookup مبني على hash table. الـ hash table بيخصّص buckets أكتر من اللازم علشان يتفادى الـ collisions، وبيحتفظ بمؤشرات لكل key وvalue. هيكل البيانات ده اسمه PyDictObject ومحدد في ملف cpython/Objects/dictobject.c في الـ source code الرسمي لـ CPython.
لما بتضيف __slots__ داخل تعريف الكلاس، Python بيستبدل الـ hash table بـ array صغير ثابت الطول من المؤشرات. الـ attribute lookup بيتحول من hashing operation لـ array offset، اللي بيخلّيه أسرع شوية كمان (5-10% في الـ benchmarks العملية حسب benchmarks Brett Slatkin في Effective Python).
اللي بيحصل بالظبط: Python بيشيل __dict__ و__weakref__ الافتراضيين، وبينشئ descriptors محددة لكل attribute في الـ slot. كل descriptor عبارة عن offset ثابت في memory layout الـ instance.
الكود التنفيذي مع الأرقام
هنقارن كلاسين بنفس الـ attributes، واحد بـ __dict__ الافتراضي والتاني بـ __slots__: