2.3 · البرمجة كائنية التوجه (الأصناف، الوراثة، dunder)

المستوى 2 · هياكل البيانات والبرمجة كائنية التوجه

2.3البرمجة كائنية التوجه (الأصناف، الوراثة، dunder)

الهدف: إنشاء الأصناف والوراثة والطرق الخاصة (__init__ و__str__…).
الوقت المقدّر: 18 دقيقة · قراءة ذاتية · إذا كان لديك 5 دقائق فقط: اقرأ «الأساسي في 30 ثانية» + المخطط.

الأساسي في 30 ثانية

  • الصف قالب والكائن قطعة : الخصائص (بيانات) + الطرق (أفعال على self) تسافر معا — انتهت القواميس + الدوال المشتتة.
  • الوراثة = هو : الابن يخصص الأب عبر super()، غير عميقة (≤ 3) — التركيب لـ له.
  • Dunders = كائنات مواطنة : ‏__str__/__eq__/__len__ تجيب print/==/len — ‏@dataclass لحاملة البيانات.

حالة مستمرة — نبيل ينمذج مبيعاته كائنات

قواميس نبيل تتشتت : دوال تعالج مبيعات دون التحقق من المبالغ أبدا، وتقارير تكرر الحسابات نفسها. نمذج : صف Vente (الولاية والمبلغ وطريقتا total و__str__ المقروءة)، وصف RapportMensuel الذي يجمع المبيعات، ثم صف VenteRemise الذي يرث من Vente ويضيف نسبة (super().__init__() تعيد استعمال الأب). انتهت القواميس + الدوال المبعثرة : البيانات والسلوكيات تعيش معا. في 2.4، سيرفض الإنشاء المبالغ السالبة بـ raise.

تتمة الخيط الرابط 2.2 : سطور نبيل تصبح كائنات — وتستمر في 2.4.

1. الصف : القالب، والكائن : القطعة

class Vente: + ‏__init__(self, ...) يحدد القالب ؛ وv = Vente("الجزائر", 1200) ينشئ القطعة. self تعني الكائن نفسه في طرقه : كل كائن يصل إلى خصائصه (self.montant) باستقلال عن الآخرين. الخصائص هي البيانات، والطرق هي السلوكيات (أفعال على self، ولا global أبدا). البيانات + السلوكيات تسافر معا : انتهت القواميس + الدوال المشتتة. نبيل ينشئ هكذا عمليتي بيع متميزتين لا تختلطان أبدا.

2. الوراثة : خصص ولا تنسخ

class VenteRemise(Vente): ترث وتخصص (النسبة والحساب المخصوم). super().__init__() تعيد استعمال منشئ الأب بدل نسخه ؛ وإعادة تعريف طريقة في الابن هي تعدد الأشكال. القاعدة : الوراثة لـ « هو » (فـ VenteRemise هي Vente)، والتركيب (« له » : فـ Rapport لها عمليات Ventes) وإلا. ثلاثة مستويات كحد أقصى : أبعد من ذلك متاهة. نبيل يضيف هكذا المبيعات المخصومة دون لمس الكود الموجود.

3. Dunder : تحدث بايثون بطلاقة

الطرق dunder (شرطتان سفليتان مزدوجتان) تدمج كائناتك في الآليات الأصلية : __str__ لعرض مقروء (print(v))، و__eq__ للمساواة (==)، و__len__ للحجم (len()). دونها، print(objet) تعرض غامض <... object at 0x...>. ولحاملة البيانات البسيطة، @dataclass تولد __init__ و__eq__ و__repr__ تلقائيا. كائنات نبيل تجيب هكذا print() و== كالأنواع الأصلية.

خطأ شائع في الفهم: « البرمجة كائنية التوجه مجرد قواميس فيها دوال — وself لا فائدة منها ». لا. القاموس لا يحمي شيئا (مفاتيح حرة ولا تحقق ودوال مشتتة) ؛ والصف يجمع البيانات + السلوكيات، ويهيئ في __init__ ويعزل كل كائن عبر self — فكائنان لا يختلطان أبدا. نسيان self مشاركة أو فقدان للحالة. قاعدة نبيل : بيانات تسافر مع قواعدها = صف ؛ وself تُكتَب في التعريف ولا تُستدعَى أبدا (بايثون تمررها وحدها).
كائنات نظيفة البيانات والسلوكيات معا الصف (قالب)‏__init__ + ‏self — الخصائص والطرق+الوراثة (هو)‏super() والتخصيص و≤ 3 مستويات+Dunder ‏(__str__…)‏print و== وlen كالأصلية الوراثة لـ هو، والتركيب لـ له.
البيانات والسلوكيات معا
نص المخطط (SEO / قارئات الشاشة / الترجمة): 1) نبيل يحدد القالب (صف Vente + ‏__init__) وينشئ القطع (كائنات) : ‏self يعزل كل كائن، والخصائص + الطرق تسافر معا. 2) يخصص بالوراثة (فـ VenteRemise هي Vente، وsuper() تعيد استعمال الأب، و≤ 3 مستويات) ويركب وإلا (فـ Rapport لها عمليات Ventes). 3) يجعل كائناته مواطنة بالـ dunders ‏(__str__ لـ print و__eq__ لـ ==) و‏@dataclass لحاملة البيانات. الدرس : نمذج كائنات بدل تشتيت القواميس والدوال.

🔎 مثال ملموس — 🔎 مثال ملموس — مبيعات نبيل التي تعرض نفسها

كائنات مقروءة وقابلة للمقارنة، كما عند نبيل :

class Vente:
    def __init__(self, wilaya, montant):
        self.wilaya = wilaya
        self.montant = float(montant)
    def __str__(self):
        return f"{self.wilaya} : {self.montant:.2f} €"

class VenteRemise(Vente):
    def __init__(self, wilaya, montant, taux=0.1):
        super().__init__(wilaya, montant)
        self.taux = taux
    def net(self):
        return self.montant * (1 - self.taux)

v = VenteRemise("الجزائر", 1000)
print(v)          # الجزائر : 1000.00 €
print(f"الصافي : {v.net():.2f} €")  # الصافي : 900.00 €

القراءة : ‏__init__ تهيئ، و__str__ تعرض، وsuper() تعيد استعمال الأب.

الدرس : الطرق = أفعال على self، ولا global أبدا.

مفردات القسم

الصف (class) / الكائن
الصف هو المخطط (القالب) ؛ والكائن (النسخة) إنجاز ملموس منشأ من هذا المخطط : v = Vente(...).

مثال بسيط: نبيل ينشئ عمليتي بيع متميزتين من الصف نفسه.

ما ليس كذلك: قاموس حر دون قواعد ولا سلوكيات.

رد فعل: مفهوم يُنمذَج = صف.

الخاصية / الطريقة
الخاصية بيان الكائن (self.montant) ؛ والطريقة دالة ملحقة بالكائن، فعل على self.

مثال بسيط: عملية بيع نبيل تحمل الولاية وتحسب net().

ما ليس كذلك: دوال عامة مشتتة بعيدا عن البيانات.

رد فعل: فعل على البيانات = طريقة.

__init__ / self
__init__ هو المنشئ، يُستدعَى عند الإنشاء ؛ وself تعني الكائن الحالي، تُكتَب في التعريف وتُمرَّر تلقائيا عند الاستدعاء.

مثال بسيط: Vente("الجزائر", 1200) تهيئ self.wilaya وself.montant.

ما ليس كذلك: وسيط يُمرَّر يدويا في كل استدعاء.

رد فعل: إنشاء كائن = ‏__init__ عبر self.

الوراثة (inheritance)
صف ابن يرث خصائص أب وطرقه ويخصصها ؛ وsuper() تعيد استعمال الأب. مخصصة لـ « هو »، غير عميقة.

مثال بسيط: VenteRemise ترث من Vente وتضيف النسبة.

ما ليس كذلك: نسخ ولصق لصف الأب.

رد فعل: هو = وراثة ؛ وله = تركيب.

الطريقة الخاصة (dunder)
طريقة بشرطتين سفليتين مزدوجتين (__str__ و__len__ و__eq__) تربط كائناتك بـ print() و== وlen() ؛ و‏@dataclass تولدها لحاملة البيانات.

مثال بسيط: print(vente) تعرض « الجزائر : 1000.00 € » بفضل __str__.

ما ليس كذلك: عرض غامض .

رد فعل: كائن قابل للعرض/المقارنة = dunder.

في التطبيق — تطبيقيا — إنشاء الأصناف والوراثة

  1. عرف صف Vente مع __init__(self, wilaya, montant) وطريقة afficher(). أنشئ كائنين متميزين وتحقق من استقلالهما.
  2. أضف __str__ لعرض مقروء (print(v) ← « الجزائر : 1000.00 € ») و__eq__ لمقارنة عمليتي بيع.
  3. أنشئ صف VenteRemise الذي يرث من Vente، ويضيف نسبة وطريقة net(). أعد استعمال الأب بـ super().__init__().
  4. أعد تعريف net() في الابن (تعدد الأشكال) واختبر @dataclass على صف حامل بيانات بسيط.
تنمذج المفاهيم أصنافا، وتنشئ كائنات، وتستعمل الوراثة وتجعل كائناتك مقروءة بـ __str__ : أسس البرمجة كائنية التوجه.

نص جاهز — الدفاع عن الصف أمام الفريق (30 ثانية)

« لمبيعات نبيل، استبدلت القواميس المشتتة بصف Vente : الولاية والمبلغ مهيآن في __init__، والحسابات طرق على self — كل كائن مستقل. الخصومات ترث بـ super()، و__str__ تعطي عرضا نظيفا. لا نلمس البيانات بعد اليوم دون المرور بالكائن. »

يُقال مع عرض قاموس مرتجل ثم الحالة نفسها صفا.

قالب للنسخ — صف ووراثة وdunder

class Vente:
    def __init__(self, wilaya, montant):
        if float(montant) < 0:
            raise ValueError("المبلغ السالب ممنوع")
        self.wilaya = wilaya
        self.montant = float(montant)
    def __str__(self):
        return f"{self.wilaya} : {self.montant:.2f} €"
    def __eq__(self, autre):
        if not isinstance(autre, Vente):
            return NotImplemented
        return (self.wilaya, self.montant) == (autre.wilaya, autre.montant)

class VenteRemise(Vente):
    def __init__(self, wilaya, montant, taux=0.1):
        super().__init__(wilaya, montant)
        self.taux = taux
    def net(self):
        return self.montant * (1 - self.taux)

عملية بيع بسيطة

عملية بيع لنبيل تحمل الولاية + المبلغ وتُعرَض بسلسلة f-string عبر __str__.

عملية بيع مخصومة

VenteRemise ترث وتضيف النسبة : super() تعيد استعمال الأب، وnet() تحسب.

تقرير شهري

التقرير له عمليات Ventes (تركيب) : يجمع دون أن يرث — له، لا هو.

حامل بيانات

ملخص بسيط يصبح @dataclass : ‏__init__ و__eq__ مولدان، وصفر كود مكرر.

✓ ممارسات جيدة

  • جمع البيانات + السلوكيات في صف (لا قاموس + دوال مشتتة أبدا).
  • الوراثة غير عميقة (≤ 3) لـ هو ؛ والتركيب لـ له ؛ وsuper() لإعادة الاستعمال.
  • إضافة __str__/__eq__ و‏@dataclass لكائنات مواطنة.

✗ أخطاء شائعة

  • إبقاء كل شيء في قاموس + دوال عامة مشتتة.
  • استعمال الوراثة لـ « له » بدل التركيب.
  • تكديس 6 مستويات وراثة غير مقروءة.

النقاط الأساسية

  • الصف هو القالب ؛ والكائن (النسخة) إنجاز منه.
  • __init__ تهيئ الكائن ؛ وself تعني الكائن الحالي (تُمرَّر تلقائيا).
  • الوراثة تسمح لصف ابن بإعادة استعمال صف أب وتوسيعه (هو وsuper()).
  • الطرق dunder ‏(__str__…) تدمج كائناتك في آليات بايثون ؛ و‏@dataclass لحاملة البيانات.

تحدي 48 ساعة — طبق غدا

نمذج مفهوما حقيقيا (مفهوم نبيل أو مفهومك) في صف مع __init__ + ‏__str__، وأنشئ كائنين مستقلين، وأضف صف ابن مع super() واختبر المساواة بـ __eq__.

قائمة الخروج من القسم
  • أستطيع شرح الصف مقابل الكائن ودور self.
  • أعرف إنشاء صف وطريقة ووراثة بـ super().
  • جعلت كائناتي مقروءة بـ __str__ (و‏@dataclass إن ناسب).
تقييم ذاتي 1-5 : هل بياناتي تسافر مع سلوكياتها ؟هل وراثتي غير عميقة ومبررة ؟

أسئلة شائعة

ما فائدة self بالضبط ؟

self تمثل الكائن الذي تُستدعَى عليه الطريقة. تسمح لكل كائن بالوصول إلى خصائصه (self.montant) باستقلال عن الآخرين. بايثون تمررها تلقائيا عند الاستدعاء : تكتبها في التعريف لا عند الاستدعاء.

هل البرمجة كائنية التوجه ضرورية للمبتدئ ؟

للسكربتات الصغيرة، لا : الدوال تكفي. لكن حالما تكبر البرامج — ولفهم المكتبات (pandas وDjango…) التي تستعملها في كل مكان — تصبح البرمجة كائنية التوجه أساسية. الاستثمار هنا يدفع على المدى الطويل.

تحقّق من فهمك

ماذا تعني « self » في طريقة ؟

موارد إضافية (اختياري، للتعمّق أكثر)

اختبار المستوى 2أسئلة جديدة وأصعب للتحقق من مكتسباتك

GUIDINEE.COM · بايثون