2.3البرمجة كائنية التوجه (الأصناف، الوراثة، dunder)
الأساسي في 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() و== كالأنواع الأصلية.
🔎 مثال ملموس — 🔎 مثال ملموس — مبيعات نبيل التي تعرض نفسها
كائنات مقروءة وقابلة للمقارنة، كما عند نبيل :
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.
في التطبيق — تطبيقيا — إنشاء الأصناف والوراثة
- عرف صف Vente مع __init__(self, wilaya, montant) وطريقة afficher(). أنشئ كائنين متميزين وتحقق من استقلالهما.
- أضف __str__ لعرض مقروء (print(v) ← « الجزائر : 1000.00 € ») و__eq__ لمقارنة عمليتي بيع.
- أنشئ صف VenteRemise الذي يرث من Vente، ويضيف نسبة وطريقة net(). أعد استعمال الأب بـ super().__init__().
- أعد تعريف net() في الابن (تعدد الأشكال) واختبر @dataclass على صف حامل بيانات بسيط.
نص جاهز — الدفاع عن الصف أمام الفريق (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 إن ناسب).
أسئلة شائعة
ما فائدة self بالضبط ؟
self تمثل الكائن الذي تُستدعَى عليه الطريقة. تسمح لكل كائن بالوصول إلى خصائصه (self.montant) باستقلال عن الآخرين. بايثون تمررها تلقائيا عند الاستدعاء : تكتبها في التعريف لا عند الاستدعاء.
هل البرمجة كائنية التوجه ضرورية للمبتدئ ؟
للسكربتات الصغيرة، لا : الدوال تكفي. لكن حالما تكبر البرامج — ولفهم المكتبات (pandas وDjango…) التي تستعملها في كل مكان — تصبح البرمجة كائنية التوجه أساسية. الاستثمار هنا يدفع على المدى الطويل.
ماذا تعني « self » في طريقة ؟