بعد أن تعلمت في الدروس السابقة معنى class وobject والفرق بين خصائص الكلاس وخصائص الكائن، ستلاحظ أن بعض الكلاسات تتشابه كثيرًا. مثلًا: الطالب والمعلم كلاهما يملك اسمًا وبريدًا إلكترونيًا وطريقة لعرض معلوماته، لكن لكل واحد منهما بيانات وسلوك إضافي مختلف.
بدل أن تكرر نفس الكود في أكثر من class، يمكنك استخدام الوراثة Inheritance. الوراثة تسمح لك بإنشاء class جديد يرث الخصائص والدوال الأساسية من class موجود، ثم تضيف إليه ما يحتاجه أو تعدّل بعض سلوكه بطريقة منظمة.
في هذا الدرس ستتعلم معنى Parent Class وChild Class، وكيف تستخدم super()، وكيف تعدّل method موروثة، ومتى تكون الوراثة اختيارًا جيدًا ومتى لا تكون كذلك.
{alertInfo} الفكرة ببساطة: إذا كانStudentيعتبر نوعًا منPerson، فمن المنطقي أن يرث الطالب الاسم والبريد ودالة التعريف من class الشخص، ثم يضيف بياناته الخاصة مثل الدرجة أو التخصص.
{getToc} $title={محتوى المقال}
ما هي الوراثة Inheritance في Python؟
الوراثة هي آلية في البرمجة كائنية التوجه تسمح لـ class جديد بأن يستفيد من خصائص ودوال class موجود مسبقًا. نسمي class الأصلي عادة:
- Parent Class أو Base Class أو الكلاس الأب.
ونسمي class الذي يرث منه:
- Child Class أو Derived Class أو الكلاس الابن.
توضح وثائق Python أن الكلاس المشتق يستطيع أن يرث من كلاس أساسي، وأنه يمكنه إعادة تعريف methods موروثة أو استدعاء method موجودة في الكلاس الأب عند الحاجة.
لماذا نستخدم الوراثة؟
الفائدة الرئيسية من الوراثة هي إعادة استخدام الكود. بدل نسخ نفس الخصائص والدوال داخل كل class، تكتب الجزء المشترك مرة واحدة داخل الكلاس الأب.
| بدون وراثة | باستخدام الوراثة |
|---|---|
تكرر name وemail ودالة عرض البيانات في كل class. |
تضع البيانات المشتركة في Person وتورّثها إلى Student وTeacher. |
| تعديل الدالة المشتركة يحتاج تعديلها في أماكن متعددة. | تعدلها في class الأب، فتستفيد منها الكلاسات الأبناء. |
| يزداد احتمال وجود اختلافات وأخطاء بين الكلاسات المتشابهة. | الكود يصبح أوضح عندما توجد علاقة حقيقية من نوع “هو نوع من”. |
لكن لا تستخدم الوراثة فقط لأن كلاسَين فيهما بعض التشابه. اسأل: هل الكلاس الابن فعلًا نوع خاص من الكلاس الأب؟ الطالب هو شخص، والسيارة ليست شخصًا. إذا كانت العلاقة ليست “هو نوع من”، فقد يكون التركيب أو تمرير كائن داخل كائن خيارًا أوضح لاحقًا.
أول مثال: Person وStudent
سننشئ أولًا class باسم Person فيها الاسم والبريد الإلكتروني ودالة تعريف بسيطة:
class Person:
def __init__(self, name, email):
self.name = name
self.email = email
def introduce(self):
print(f"مرحبًا، أنا {self.name}.")
الآن ننشئ class باسم Student ترث من Person. نكتب اسم الأب داخل الأقواس بعد اسم class:
class Student(Person):
pass
حتى بدون كتابة أي دوال داخل Student، فإنها ترث ما هو موجود في Person. جرّب:
student = Student("علي", "ali@example.com")
print(student.name)
print(student.email)
student.introduce()
الناتج:
علي
ali@example.com
مرحبًا، أنا علي.
لم نكتب __init__ أو introduce() داخل Student، لكن الطالب استطاع استخدامها لأنها موروثة من Person.
إضافة خصائص جديدة إلى Child Class
الطالب لا يملك فقط الاسم والبريد؛ قد يملك تخصصًا ودرجة. لذلك نضيف خصائص خاصة به داخل class الابن.
هنا نحتاج إلى دالة __init__ داخل Student. لكن إذا كتبناها، يجب أن نهيئ بيانات الأب أيضًا. لهذا نستخدم super().
class Person:
def __init__(self, name, email):
self.name = name
self.email = email
def introduce(self):
print(f"مرحبًا، أنا {self.name}.")
class Student(Person):
def __init__(self, name, email, major, score):
super().__init__(name, email)
self.major = major
self.score = score
student = Student(
"سارة",
"sara@example.com",
"علوم الحاسوب",
92
)
print(student.name)
print(student.major)
print(student.score)
ما هي super() ولماذا نستخدمها؟
الدالة super() تمنحك طريقة للوصول إلى الكلاس الأب من داخل الكلاس الابن. في هذا المثال:
super().__init__(name, email)
تعني: “نفّذ دالة __init__ الموجودة في Person، وأرسل إليها الاسم والبريد الإلكتروني”. وبذلك لا تحتاج إلى كتابة السطرين التاليين مجددًا داخل class الابن:
self.name = name
self.email = email
بعد استدعاء الأب، تكمل class الابن بخصائصها الإضافية مثل major وscore.
{alertWarning} خطأ شائع: عندما تكتب__init__جديدة داخل class الابن، لا تُستدعى__init__الخاصة بالأب تلقائيًا. استخدمsuper().__init__(...)إذا كنت تحتاج تهيئة خصائص الكلاس الأب.
استخدام methods موروثة من Parent Class
الطالب ما زال قادرًا على استخدام introduce() الموروثة من Person:
student.introduce()
وسيطبع:
مرحبًا، أنا سارة.
ويمكننا إضافة method جديدة للطالب فقط، مثل التحقق من النجاح:
class Student(Person):
def __init__(self, name, email, major, score):
super().__init__(name, email)
self.major = major
self.score = score
def is_passed(self):
return self.score >= 60
هنا introduce() جاءت من الأب، بينما is_passed() تخص الطالب فقط.
تعديل Method موروثة: Method Overriding
أحيانًا تكون method الأب مناسبة كبداية، لكن الكلاس الابن يحتاج سلوكًا أكثر تحديدًا. يمكنك كتابة method بالاسم نفسه داخل class الابن؛ وهذا يسمى Method Overriding.
في المثال التالي، الكلاس الأب يعرّف الشخص بشكل عام، بينما الطالب يضيف التخصص إلى رسالة التعريف:
class Person:
def __init__(self, name, email):
self.name = name
self.email = email
def introduce(self):
print(f"أنا {self.name}.")
class Student(Person):
def __init__(self, name, email, major):
super().__init__(name, email)
self.major = major
def introduce(self):
print(
f"أنا {self.name}، طالب في تخصص {self.major}."
)
عند تشغيل:
student = Student(
"علي",
"ali@example.com",
"الذكاء الاصطناعي"
)
student.introduce()
سيستخدم Python دالة introduce() الموجودة في Student بدل الدالة الموجودة في Person.
كيف تضيف سلوك الابن إلى سلوك الأب؟
بدل نسخ رسالة الأب بالكامل، يمكنك استدعاء method الأب عبر super() ثم تضيف سطرًا جديدًا:
class Student(Person):
def __init__(self, name, email, major):
super().__init__(name, email)
self.major = major
def introduce(self):
super().introduce()
print(f"تخصصي هو: {self.major}")
بهذه الطريقة تستفيد من سلوك الأب وتضيف إليه سلوكًا خاصًا بالابن.
مثال عملي كامل: Person وStudent وTeacher
المثال التالي يوضح كيف يمكن لأكثر من class أن يرث من الأب نفسه:
class Person:
academy_name = "أكاديمية بايثون العرب"
def __init__(self, name, email):
self.name = name
self.email = email
def show_contact(self):
print(f"الاسم: {self.name}")
print(f"البريد: {self.email}")
class Student(Person):
def __init__(self, name, email, major, score):
super().__init__(name, email)
self.major = major
self.score = score
def show_role(self):
status = "ناجح" if self.score >= 60 else "يحتاج مراجعة"
print(f"طالب في: {self.major}")
print(f"الحالة: {status}")
class Teacher(Person):
def __init__(self, name, email, subject):
super().__init__(name, email)
self.subject = subject
def show_role(self):
print(f"مدرس مادة: {self.subject}")
student = Student(
"سارة",
"sara@example.com",
"علوم الحاسوب",
88
)
teacher = Teacher(
"خالد",
"khaled@example.com",
"Python"
)
print(Person.academy_name)
student.show_contact()
student.show_role()
print("-" * 30)
teacher.show_contact()
teacher.show_role()
في هذا المثال:
Personيحتوي على البيانات والسلوك المشترك.Studentيرث الاسم والبريد ويضيف التخصص والدرجة.Teacherيرث الاسم والبريد ويضيف المادة التي يدرسها.- الكل يستطيع الوصول إلى
academy_nameلأنها class attribute موروثة من الأب.
كيف تعرف هل كائن يرث من class معين؟
توفر Python دالة isinstance() للتحقق هل كائن معين ينتمي إلى class أو إلى class يرث منه.
print(isinstance(student, Student))
print(isinstance(student, Person))
الناتج سيكون:
True
True
السبب أن student هو كائن من Student، وStudent يرث من Person.
وتستطيع أيضًا التحقق من العلاقة بين classين باستخدام issubclass():
print(issubclass(Student, Person))
أخطاء شائعة عند استخدام الوراثة
1. نسيان كتابة Parent Class بين الأقواس
هذا الكود لا يجعل Student يرث من Person:
class Student:
pass
الصحيح:
class Student(Person):
pass
2. نسيان super().__init__ داخل Child Class
إذا أنشأت __init__ داخل الابن ثم استخدمت خصائص الأب لاحقًا، قد يظهر خطأ مثل:
AttributeError: 'Student' object has no attribute 'name'
لأنك لم تنفذ تهيئة الأب التي تنشئ self.name وself.email.
3. تكرار كود الأب بدل استدعائه
يمكنك كتابة خصائص الأب يدويًا داخل الابن، لكن هذا يجعل الصيانة أصعب. الأفضل غالبًا استخدام super().__init__() ما دام الابن يحتاج نفس التهيئة.
4. استخدام الوراثة لعلاقة غير منطقية
لا تجعل Car ترث من Person لمجرد أن كليهما يملك اسمًا. الوراثة تعبر عن علاقة “هو نوع من”، مثل Student هو نوع من Person.
5. تعديل method دون استدعاء الأب عند الحاجة
عندما تعيد تعريف method، تختفي نسخة الأب من الاستخدام المباشر على الكائن. إذا أردت الإبقاء على جزء من سلوك الأب، استدعها عبر super().method_name().
متى لا تحتاج إلى الوراثة؟
الوراثة مفيدة، لكنها ليست الحل لكل شيء. لا تستخدمها فقط لتقليل عدد الأسطر. إذا كانت العلاقة أقرب إلى “يحتوي على” بدل “هو نوع من”، فكر في وضع كائن داخل كائن بدل الوراثة.
مثلًا: الطالب ليس نوعًا من Course، لكنه يمكن أن يسجل في دورة. هنا يمكن أن تحتوي class الطالب على قائمة دورات أو كائنات دورات، ولا نحتاج أن يرث من Course.
تمرين عملي
أنشئ class أب باسم Vehicle يحتوي على:
- خصائص:
brandوyear. - دالة باسم
show_info()تعرض معلومات المركبة.
ثم أنشئ class ابن باسم Car يرث من Vehicle ويضيف:
- خاصية باسم
doors. - تعديل
show_info()حتى تعرض عدد الأبواب أيضًا.
حل مقترح
class Vehicle:
def __init__(self, brand, year):
self.brand = brand
self.year = year
def show_info(self):
print(f"الماركة: {self.brand}")
print(f"السنة: {self.year}")
class Car(Vehicle):
def __init__(self, brand, year, doors):
super().__init__(brand, year)
self.doors = doors
def show_info(self):
super().show_info()
print(f"عدد الأبواب: {self.doors}")
car = Car("Toyota", 2024, 4)
car.show_info()
روابط داخلية مفيدة من بايثون العرب
- أساسيات بايثون 34: شرح class وobject في Python للمبتدئين
- كورس أساسيات بايثون للمبتدئين
- شرح الدوال Functions في Python للمبتدئين
- أساسيات بايثون: شرح try وexcept في Python
الخلاصة
- الوراثة تسمح للكلاس الابن أن يرث خصائص ودوال الكلاس الأب.
- نكتب class الابن بهذا الشكل:
class Student(Person):. - استخدم
super().__init__(...)لتهيئة خصائص الأب من داخل الابن. - يمكن للابن إضافة خصائص ودوال خاصة به دون تعديل الكلاس الأب.
- يمكنك تعديل method موروثة عبر Method Overriding، مع استدعاء نسخة الأب عبر
super().method_name()عند الحاجة. - استخدم الوراثة عندما تكون العلاقة منطقية: الابن “هو نوع من” الأب.
{alertSuccess} خطوتك التالية: عدّل مثالPersonوأنشئ class جديدة باسمAdminترث منه، ثم أضف لها خاصيةpermissionsودالة تعرض صلاحيات المسؤول. هكذا ستتأكد أنك فهمت الفرق بين البيانات المشتركة والبيانات الخاصة بكل نوع.
مصادر خارجية رسمية للتوسع
- Inheritance — Python Tutorial
- super() — Python Built-in Functions
- isinstance() — Python Built-in Functions
أسئلة شائعة
ما هي الوراثة Inheritance في Python؟
هي طريقة لإنشاء class جديد يرث الخصائص والدوال من class موجود، ثم يضيف أو يغير ما يحتاجه. مثل Student الذي يرث من Person.
ما الفرق بين Parent Class وChild Class؟
Parent Class هو الكلاس الذي يحتوي على السلوك والبيانات الأساسية المشتركة. Child Class هو الكلاس الذي يرث منه ويضيف خصائص أو methods خاصة به.
لماذا نستخدم super في Python؟
نستخدم super() لاستدعاء method من الكلاس الأب، خصوصًا super().__init__() لتهيئة الخصائص المشتركة بدل تكرارها داخل الكلاس الابن.
هل يجب أن يرث كل class من class آخر؟
لا. استخدم الوراثة فقط عندما توجد علاقة منطقية من نوع “هو نوع من”. إذا كانت العلاقة “يحتوي على”، فكر في استخدام composition بدلًا من الوراثة.
هل يمكن للابن تعديل method موجودة في الأب؟
نعم. اكتب method بالاسم نفسه داخل child class. هذا يسمى Method Overriding، ويمكنك استدعاء نسخة الأب عبر super().method_name() إذا أردت الجمع بين السلوكين.



