Menu
العربية

الكلاسات في بايثون: __init__ والوراثة و @dataclass

دليل مبسّط للكلاسات في بايثون: كيف تعرّفها، وتُنشئ منها كائنات، ودور __init__ و self، والوراثة، ومتى تستغني عنها بـ @dataclass.

الكلاس في بايثون يجمع بين البيانات والعمليات التي تُجرى عليها

تتيح لك الكلاسات في بايثون تعريف نوع معيّن من الكائنات — مستخدم، حساب بنكي، إعدادات، أو طلب — مع كل ما يمكن لهذا الكائن أن يفعله. هذا "الكائن" هو نسخة (instance) من الكلاس، بينما تُسمّى الأفعال التي يقوم بها ميثودز (methods).

وإليك أبسط شكل ممكن لكلاس:

main.py
Output
Click Run to see the output here.

نفكّكها خطوة بخطوة:

  • class User: هو بداية تعريف الكلاس. أسماء الكلاسات تُكتب بصيغة PascalCase حسب العُرف المتّبع.
  • __init__ هو المُهيِّئ (initializer). يُستدعى تلقائيًا عند إنشاء نسخة (instance) جديدة، ومهمّته ضبط خصائص النسخة عبر self.whatever = ....
  • greet هو ميثود (method)، وself هو الطريقة التي يُشير بها الميثود إلى النسخة التي استُدعي عليها.
  • User("Rosa", "rosa@example.com") يُنشئ نسخة جديدة، وبايثون تستدعي __init__ وتمرّر لها النسخة الجديدة عبر self مع باقي الوسائط.
  • user.greet() يستدعي الميثود، وبايثون تمرّر user تلقائيًا كقيمة لـ self.

self ليست إلا المُعامل الأول

self ليست كلمة محجوزة في بايثون، بل هي مجرد الاسم المُتعارف عليه للمُعامل الأول في ميثودات النسخة، وهو يُمثّل النسخة التي يعمل عليها الميثود. تقنيًا يمكنك تسميته أيّ شيء، لكن الجميع يستخدم self لأن… الجميع يستخدمه.

كل ميثود نسخة يأخذ self كأول مُعامل له، وبهذا يعرف الميثود على أيّ نسخة سيقرأ أو سيُعدّل بياناتها.

إضافة سلوك للكلاس

الميثودات تستطيع قراءة الحالة وتعديلها:

main.py
Output
Click Run to see the output here.

__repr__ هي دالة خاصة أخرى، ومهمتها الإجابة عن سؤال: "كيف أُعرض هذا الكائن عند طباعته؟". تعريف نسخة جيدة منها يوفّر عليك الكثير من العناء أثناء التنقيح.

الفرق بين class attributes و instance attributes في بايثون

الخصائص التي تُعرَّف داخل جسم الكلاس (خارج __init__) تكون مشتركة بين جميع النسخ (instances)، أما الخصائص التي تُسنَد إلى self فتكون خاصة بكل نسخة على حدة:

main.py
Output
Click Run to see the output here.

استخدم خصائص الكلاس للقيم المشتركة فعليًا — الثوابت والعدّادات وإعدادات التكوين. أما البيانات الخاصة بكل كائن فمكانها داخل __init__.

الوراثة في بايثون

يمكن لأي كلاس أن يرث من كلاس آخر، فيحصل على توابعه وخصائصه جاهزة، ثم يضيف إليها أو يعيد تعريف ما يشاء منها:

main.py
Output
Click Run to see the output here.

تمنحك super() وصولاً إلى الكلاس الأب، وتُستخدم عادةً داخل __init__ لتهيئة خصائص الكلاس الأب قبل إضافة خصائصك الخاصة:

main.py
Output
Click Run to see the output here.

الوراثة أداة مفيدة، لكن من السهل الإفراط في استخدامها. كثيرًا ما يلجأ المبرمج المبتدئ في بايثون إلى الوراثة في حالات يكون فيها التركيب (composition) — أي الاحتفاظ بكائن كخاصية داخل كلاس آخر — أوضح وأبسط. ابدأ ببنية كلاسات مسطّحة، ولا تلجأ إلى الوراثة في بايثون إلا عندما تكون لديك علاقة "هو نوع من" (is-a) حقيقية.

Dataclasses: خيار افتراضي أنظف لتمثيل البيانات

عندما يكون كل ما تريده من الكلاس هو الاحتفاظ ببعض الخصائص مع سلوك مقبول للمقارنة والتمثيل النصي، فإن @dataclass يوفّر عليك الكثير من الكود المتكرر:

main.py
Output
Click Run to see the output here.

قارن هذا بكتابة __init__ و__repr__ و__eq__ يدويًا. الـ dataclasses هي الخيار الأول المناسب في الحالات التي كنت ستكتب فيها class Thing لا يحتوي إلا على __init__ لتعيين الخصائص.

الخصائص المحسوبة باستخدام @property في بايثون

أحيانًا تحتاج إلى "خاصية" تكون في الحقيقة محسوبة. يتيح لك @property أن تجعلها تبدو وكأنها خاصية عادية:

main.py
Output
Click Run to see the output here.

استخدم الـ properties في المواضع اللي كنت ستكتب فيها obj.get_something() — استبدالها بـ property يجعل واجهة الكلاس أكثر طبيعية في الاستخدام. لكن لا تستخدمها لإخفاء عمليات ثقيلة؛ لأن المستخدم يتوقع أن الوصول إلى أي خاصية يكون سريعاً.

الخصوصية بالاصطلاح لا بالإجبار

لا يوجد في بايثون مفهوم private حقيقي. الاصطلاح المتعارف عليه هو أن أي خاصية تبدأ بشرطة سفلية (_) تُعتبر خاصة بشكل ضمني — بمعنى أن القارئ يفهم أنه لا يجب التعامل معها من خارج الكلاس:

class Cache:
    def __init__(self):
        self._store = {}

    def put(self, key, value):
        self._store[key] = value

    def get(self, key, default=None):
        return self._store.get(key, default)

الأسماء التي تبدأ بشرطتين سفليتين (__name) تُفعِّل ما يُعرف بـ name mangling، أي أن بايثون تُضيف اسم الكلاس إلى اسم الخاصية تلقائيًا. هذه الآلية موجودة لتفادي تضارب الأسماء عند الوراثة، وليست وسيلة حماية أو تشفير.

متى لا تحتاج إلى إنشاء كلاس في بايثون؟

إذا كان كل ما لديك مجموعة بيانات مترابطة لا أكثر، فيكفيك dataclass أو قاموس عادي أو namedtuple. وإذا كان لديك دالة واحدة فقط، فلا داعي لتغليفها داخل كلاس. استخدم الكلاسات في بايثون عندما تجتمع لديك الحالة والسلوك معًا — خصوصًا حين تتوقع إنشاء عدد كبير من الكائنات (instances) من النوع نفسه.

مثال أخير

إليك buffer بسيط لتسجيل الأحداث يتصرف كأنه ملف:

main.py
Output
Click Run to see the output here.

لاحظ __len__ — هذه دالة سحرية أخرى (magic method). بمجرد تعريفها يصبح استدعاء len(logger) ممكنًا، لأن len(x) في الحقيقة ليس إلا نداءً لـ x.__len__(). بايثون تحتوي على عشرات من هذه الخطّافات (hooks)، وستتعرف عليها تدريجيًا كلما احتجت إليها.

التالي: المولدات (Generators)

الكلاسات تجمع بين البيانات والسلوك في وحدة واحدة. أما الفصل القادم فسيأخذك إلى نوع مختلف تمامًا من التجريد — وهو التكرار (iteration) — بدءًا من المولدات: دوال تُنتج القيم واحدة تلو الأخرى، وتتوقف مؤقتًا بين كل قيمة والتي تليها. وهي تنسجم بشكل رائع مع عبارة with ومديري السياق (context managers) الذين ستتعرف عليهم مباشرة بعد ذلك.

الأسئلة الشائعة

ما هو الكلاس (class) في بايثون؟

الكلاس هو قالب أو مخطّط لإنشاء كائنات تجمع البيانات (الخصائص) والسلوك (الميثودز) في مكانٍ واحد. مثلاً class User: يُعرِّف كلاس المستخدم، بينما User(...) يُنشئ نسخة (instance) منه. الكلاسات هي الأداة الأساسية في بايثون لنمذجة أي شيء له حالة وسلوك في آنٍ واحد.

ما معنى self في بايثون؟

self هو البارامتر الأول في أي ميثود تابعة للنسخة (instance method). عندما تستدعي user.greet()، تُمرِّر بايثون الكائن user تلقائياً كـ self. وداخل الميثود يمكنك الوصول إلى خصائص ذلك الكائن عبر self.name مثلاً. الاسم self مجرد اتفاق بين المبرمجين وليس كلمة محجوزة، لكن الكلّ في مجتمع بايثون يلتزم به.

هل بايثون لغة كائنية التوجّه (OOP)؟

نعم، وكل شيء في بايثون هو كائن بما في ذلك الأرقام والنصوص وحتى الدوال. لكن بايثون لا تُجبرك على استخدام البرمجة الكائنية، فتستطيع الاستفادة منها عند الحاجة فقط. كثير من البرامج الواقعية بلغة بايثون تستخدم الكلاسات بحذر، وتعتمد على الدوال العادية وهياكل البيانات البسيطة كلما أمكن ذلك.

تعلّم البرمجة مع Coddy

ابدأ الآن