🐍 الفئات الداخلية (Inner Classes) في بايثون: تنظيم كودك بشكل أنيق! 🐍

اليوم سنتعرف على مفهوم رائع في البرمجة كائنية التوجه (OOP) وهو الفئات الداخلية (Inner Classes). إذا كنت تتساءل عن كيفية تنظيم الكود بشكل أفضل وجعل العلاقات بين الكائنات أكثر وضوحاً، فأنت في المكان الصحيح! 🌟

الفئة الداخلية هي ببساطة فئة تُعرَّف داخل فئة أخرى. تخيلها كصندوق صغير داخل صندوق كبير. الصندوق الكبير هو الفئة الخارجية (Outer Class)، والصندوق الصغير هو الفئة الداخلية (Inner Class).


🤔 لماذا نستخدم الفئات الداخلية؟

قبل أن نتعمق في كيفية كتابتها، دعنا نفهم الفائدة منها:

  1. التجميع المنطقي (Logical Grouping): إذا كانت الفئة (أ) لا تكون مفيدة إلا عند استخدامها مع الفئة (ب)، فمن المنطقي وضعها داخلها. مثال: محرك (Engine) داخل سيارة (Car).
  2. زيادة التغليف (Enhanced Encapsment): يمكن إخفاء الفئة الداخلية عن العالم الخارجي، فلا يمكن الوصول إليها إلا من خلال الفئة الخارجية.
  3. قراءة الكود (Code Readability): يجعل الكود أكثر تنظيماً وسهولة في الفهم، لأن العلاقة بين الكائنات تكون واضحة.

📝 أنواع الفئات الداخلية في بايثون

في بايثون، لدينا نوعان رئيسيان من الفئات الداخلية:

  1. الفئات المتداخلة (Nested Classes)
  2. الفئات المحلية (Local Classes)

دعنا نستكشف كل نوع على حدة.

1. الفئات المتداخلة (Nested Classes)

هي الفئة التي تُعرَّف في نفس مستوى تعريف الدوال (Methods) داخل الفئة الخارجية. هذا هو النوع الأكثر شيوعاً.

مثال بسيط: جامعة وطالب

لنفترض أننا نريد تمثيل جامعة تحتوي على طلاب. العلاقة هنا واضحة: الطالب (Student) كائن ينتمي logically إلى الجامعة (University).

# الفئة الخارجية (Outer Class): University
class University:
    
    # مُنشئ الفئة الخارجية
    def __init__(self, name):
        self.name = name
        # قائمة لتخزين كائنات الطلاب
        self.students = [] 

    # الفئة الداخلية (Inner Class): Student
    class Student:
        def __init__(self, student_name, student_id):
            self.student_name = student_name
            self.student_id = student_id
        
        def display_info(self):
            print(f"Student Name: {self.student_name}, ID: {self.student_id}") # اسم الطالب والرقم الجامعي

    # دالة في الفئة الخارجية لإضافة طالب جديد
    def add_student(self, name, id):
        # ننشئ كائن من الفئة الداخلية Student
        new_student = self.Student(name, id)
        self.students.append(new_student)
        print(f"تم إضافة الطالب {name} إلى جامعة {self.name}")

# الآن لنستخدم الكود
# إنشاء كائن من الفئة الخارجية University
my_university = University("Codex Academy")

# استخدام الدالة add_student التي بداخلها ننشئ كائن Student
my_university.add_student("Ahmed", 1001)
my_university.add_student("Fatima", 1002)

# الوصول إلى معلومات الطالب الأول
# my_university.students[0] هو كائن من نوع Student
my_university.students[0].display_info() # سيطبع: Student Name: Ahmed, ID: 1001

ملاحظة مهمة: كائن الفئة الداخلية (مثل Student) لا يمكنه الوصول مباشرة إلى attributes أو methods الخاصة بالكائن الخارجي (مثل name في University) unless you pass the outer instance to it. هذا مفهوم متقدم سنتجنب الخوض فيه الآن للحفاظ على البساطة.


2. الفئات المحلية (Local Classes)

هذا نوع أقل شيوعاً، ولكن من المهم معرفته. هنا، يتم تعريف الفئة الداخلية داخل دالة (Method) تابعة للفئة الخارجية. نطاق وجودها يقتصر على تلك الدالة فقط.

مثال: مهمة داخل مشروع

class Project:
    def __init__(self, project_name):
        self.project_name = project_name

    def create_task(self, task_description):
        # فئة محلية (Local Class) معرّفة داخل الدالة create_task
        class Task:
            def __init__(self, description):
                self.description = description
            def show_task(self):
                print(f"Task: {self.description} for project '{self.project_name}'") # خطأ محتمل! انظر الشرح أدناه

        # إنشاء كائن من الفئة المحلية Task
        new_task = Task(task_description)
        return new_task

# الاستخدام
my_project = Project("تطبيق ويب")
task_one = my_project.create_task("تصميم واجهة المستخدم")
task_one.show_task()

تحذير هام: في المثال أعلاه، محاولة الوصول إلى self.project_name من داخل دالة show_task في الفئة Task ستسبب خطأ! لأن الكائن Task ليس لديه معرفة تلقائية بالكائن Project الذي أنشأه.

الغرض من هذا المثال هو فقط أن ترى الشكل العام للفئات المحلية. في الغالب، سيكون استخدامك للفئات المتداخلة (Nested Classes) هو السائد.


💡 متى يجب استخدام الفئات الداخلية؟

استخدم الفئات الداخلية عندما:

  • توجد علاقة قوية جداً: مثل (عجلة - سيارة)، (عقدة - قائمة مترابطة).
  • لا حاجة لاستخدام الفئة الداخلية بمفردها في أي جزء آخر من برنامجك.

تجنب استخدامها إذا كانت الفئة الداخلية معقدة أو يمكن استخدامها independently، ففي هذه الحالة من الأفضل جعلها فئة مستقلة (Separate Class).


🧪 خلاصة الدرس

  • الفئة الداخلية (Inner Class) هي فئة تُعرَّف داخل فئة أخرى.
  • الغرض الرئيسي هو التجميع المنطقي وزيادة تنظيم الكود.
  • أهم نوع هو الفئات المتداخلة (Nested Classes) التي تُعرَّف داخل جسم الفئة الخارجية.
  • كائن الفئة الداخلية لا يملك وصولاً تلقائياً إلى كائن الفئة الخارجية.