Programming Basics SQL HTML CSS JavaScript React Python C++ Java JavaFX Swing Problem Solving English English Conversations Computer Fundamentals Linux Learn Typing

بايثونالتجريد

  • مفهوم التجريد
  • تعريف Abstract Class
  • تعريف Abstract Method
  • أمثلة تطبيقية على التجريد

مفهوم التجريد

التجريد ( Abstraction ) يُستخدم لإنشاء نماذج أكثر عمومية و مرونة للكود. يركز التجريد على تحديد الأوامر الرئيسية التي ستتنفذ في الدوال بدون الكشف عن تفاصيل تنفيذها الداخلية. يسمح ذلك للمبرمجين باستخدام الدوال بشكل مرن بدون الحاجة لمعرفة تفاصيل عملها الداخلية.

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

أسلوب التجريد يتم من خلال تعريف دوال مجرّدة ( Abstract Methods ) في الكلاس الأب و إجبار الكلاس الإبن على أن يفعل Override لهذه الدوال بالشكل الذي يناسبه. بالتالي عندما تنشئ كلاس يرث من كلاس فيه دوال مجرّدة سيظهر أمامك تحذير ينبهك أنك يجب أن تفعل Override لهذه الدوال حتى لا يظهر لك خطأ وقت التشغيل.


فوائد التجريد

  • تبسيط الكود - يُساعد التجريد على تبسيط الكود من خلال إخفاء التفاصيل المعقدة في الكود و جعل المبرمج يتعامل معها بشكل سطحي من خلال دوال سهلة الإستخدام.
  • إعادة الاستخدام - يُمكن إعادة استخدام الكود المجرد بسهولة في مشاريع مختلفة دون الحاجة إلى تعديله لكل سياق محدد.
  • تسهيل الصيانة - يُسهل التجريد صيانة الكود بسبب أن الكود نفسه يكون مقسم لعدة دوال مرتبطة داخلياً ببعضها و وظائف هذه الدوال تكون مكتوبة بشكل منفصل مما يجعلها لا تؤثر على طريقة ربط الدوال ببعضها.
  • القابلية للتمديد - يُمكن توسيع الكود المجرد بسهولة بإضافة دوال جديدة دون التأثير على الكود الموجود.

مصطلحات تقنية

  • الكلاس العادي يقال له Concrete Class.
  • الكلاس المعرف ككلاس مجرّد يقال له Abstract Class.
  • الدالة المعرفة كدالة مجرّدة يقال لها Abstract Method.

تعريف Abstract Class

لتحويل الكلاس العادي إلى كلاس مجرّد، يجب جعل الكلاس يرث من كلاس إسمه ABC الموجود في الأساس في موديول جاهز إسمه abc.

الكلاس ABC تم تسميته هكذاً إختصاراً لجملة ( Abstract Base Classes ) التي تعني الكلاس الأب لجميع الكلاسات المجرّدة.


نقاط مهمة حول الكلاس المجرّد

  • الكلاس المجرّد يمكنه أن يحتوي على دوال عادية، و يمكنه أن يحتوي على دوال نوعها Abstract.
  • الكلاس المجرّد لا يمكن إنشاء كائنات منه في حال كان يحتوي على دوال نوعها Abstract.
  • بما أنه لا يمكن إنشاء كائنات من الكلاس المجرّد في جميع الحالات، فهذا يعني أن الإستفادة الحقيقية من هذا الكلاس تكون بوراثته.
  • الكلاس الذي يرث من كلاس مجرّد مجبر على أن يفعل Override لجميع الدوال المعرفة فيه Abstract.

في المثال التالي قمنا بتعريف كلاس مجرّد إسمه ParentClass يحتوي على دالة إسمها print_msg.
بعدها قمنا بإنشاء كلاس إسمه ChildClass يرث من الكلاس ParentClass.

ملاحظة: الكلاس ChildClass غير مجبر على أن يفعل Override للدالة print_msg() لأنها ليست معرفة كدالة مجرّدة.

مثال

ParentClass.py
# حتى نستطيع الوراثة منه abc الموجود في الموديول ABC هنا قمنا بتضمين الكلاس
from abc import ABC
# حتى يصبح كلاس مجرّد ABC و جعلناه يرث من الكلاس ParentClass هنا قمنا بإنشاء كلاس إسمه
class ParentClass(ABC):
# هنا قمنا بتعريف دالة عادية تطبع جملة عند إستدعائها
def print_msg(self):
print('Normal method defined in an abstract class')
# حتى نستطيع الوراثة منه abc الموجود في الموديول ABC هنا قمنا بتضمين الكلاس from abc import ABC # حتى يصبح كلاس مجرّد ABC و جعلناه يرث من الكلاس ParentClass هنا قمنا بإنشاء كلاس إسمه class ParentClass(ABC): # هنا قمنا بتعريف دالة عادية تطبع جملة عند إستدعائها def print_msg(self): print('Normal method defined in an abstract class')
ChildClass.py
# حتى نستطيع الوراثة منه ParentClass الموجود في الموديول ParentClass هنا قمنا بتضمين الكلاس
from ParentClass import ParentClass
# ParentClass يرث من الكلاس ChildClass هنا قمنا بإنشاء كلاس فارغ إسمه
class ChildClass(ParentClass):
pass
# حتى نستطيع الوراثة منه ParentClass الموجود في الموديول ParentClass هنا قمنا بتضمين الكلاس from ParentClass import ParentClass # ParentClass يرث من الكلاس ChildClass هنا قمنا بإنشاء كلاس فارغ إسمه class ChildClass(ParentClass): pass
Test.py
# حتى نستطيع إنشاء كائن منه ChildClass هنا قمنا بتضمين الكلاس
from ChildClass import ChildClass
# منه print_msg() بعدها قمنا باستدعاء الدالة .obj إسمه ChildClass هنا قمنا بإنشاء كائن من الكلاس
obj = ChildClass()
obj.print_msg()
# حتى نستطيع إنشاء كائن منه ChildClass هنا قمنا بتضمين الكلاس from ChildClass import ChildClass # منه print_msg() بعدها قمنا باستدعاء الدالة .obj إسمه ChildClass هنا قمنا بإنشاء كائن من الكلاس obj = ChildClass() obj.print_msg()

نتيجة تشغيل الملف Test.

Normal method defined in an abstract class

في المثال السابق كان باستطاعتنا إنشاء كائن من الكلاس ParentClass لأنه لا يحتوي على دوال مجرّدة. و لكن كما سبق و قلنا أنه بشكل عام يتم إنشاء الكلاس المجرّد في الأساس حتى يتم وراثته و ليس من أجل إنشاء كائنات منه و لهذا لم نفعل ذلك.

تعريف Abstract Method

لبناء دالة مجرّدة بحيث أن الكلاس الذي يرثها يكون مجبر و مسؤول عن كتابة محتواها نضع الكلمة المفتاحية @abstractmethod فوقها و فيها نضع الكلمة المفتاحية pass فقط.

إذا أردت بناء دالة مجرّدة و جعل الكلاس الذي يرثها مجبر على تعريفها من جديد مع إمكانية الإستفادة من الكود الموجودة فيها فقم بوضع الكلمة @abstractmethod فوقها فقط.


نقاط مهمة حول الدوال المجرّدة

  • إذا وضعت الكلمة @abstractmethod فوق الدالة, فهذا يعني أنها دالة مجرّدة و ليس دالة عادية.
  • الكلاس الذي يرث من كلاس مجرّد، يجب أن يفعل Override لكل الدوال المجرّدة التي ورثها منه.

في المثال التالي قمنا بتعريف كلاس مجرّد إسمه ParentClass يحتوي على 3 دوال كالتالي:

  • دالة عادية إسمها m1.
  • دالة مجردة و فارغة إسمها m2.
  • دالة مجردة و فيها محتوى إسمها m3.

بعدها قمنا بإنشاء كلاس إسمه ChildClass يرث من الكلاس ParentClass.

ملاحظة: الكلاس ChildClass مجبر على أن يفعل Override لكل دالة مجرّدة ورثها من الكلاس ParentClass.

مثال

ParentClass.py
# حتى نستطيع استخدامهما abc الموجودين في الموديول @abstractmethod و الكلمة ABC هنا قمنا بتضمين الكلاس
from abc import ABC, abstractmethod
# حتى يصبح كلاس مجرّد ABC و جعلناه يرث من الكلاس ParentClass هنا قمنا بإنشاء كلاس إسمه
class ParentClass(ABC):
# m1 هنا قمنا بتعريف دالة عادية إسمها
def m1(self):
print('m1: Normal method defined by ParentClass')
# m2 هنا قمنا بتعريف دالة مجردة و فارغة إسمها
@abstractmethod
def m2(self):
pass
# m3 هنا قمنا بتعريف دالة مجردة و فيها أمر طباعة إسمها
@abstractmethod
def m3(self):
print('m3: Default content is written by ParentClass')
# حتى نستطيع استخدامهما abc الموجودين في الموديول @abstractmethod و الكلمة ABC هنا قمنا بتضمين الكلاس from abc import ABC, abstractmethod # حتى يصبح كلاس مجرّد ABC و جعلناه يرث من الكلاس ParentClass هنا قمنا بإنشاء كلاس إسمه class ParentClass(ABC): # m1 هنا قمنا بتعريف دالة عادية إسمها def m1(self): print('m1: Normal method defined by ParentClass') # m2 هنا قمنا بتعريف دالة مجردة و فارغة إسمها @abstractmethod def m2(self): pass # m3 هنا قمنا بتعريف دالة مجردة و فيها أمر طباعة إسمها @abstractmethod def m3(self): print('m3: Default content is written by ParentClass')
ChildClass.py
# حتى نستطيع الوراثة منه ParentClass الموجود في الموديول ParentClass هنا قمنا بتضمين الكلاس
from ParentClass import ParentClass
# ParentClass يرث من الكلاس ChildClass هنا قمنا بإنشاء كلاس إسمه
class ChildClass(ParentClass):
# ParentClass لأن هذه الدالة كانت معرفة كدالة مجرّدة في الكلاس m2() للدالة Override هنا فعلنا
def m2(self):
print('m2: Its content is written by ChildClass')
# ParentClass لأن هذه الدالة كانت معرفة كدالة مجرّدة في الكلاس m3() للدالة Override هنا فعلنا
def m3(self):
super().m3() # و بعدها قمنا بإضافة أمر طباعة ParentClass الموجودة في الكلاس m3() لاحظ أننا قمنا باستدعاء الدالة
print('m3: ChildClass add his own code too')
# حتى نستطيع الوراثة منه ParentClass الموجود في الموديول ParentClass هنا قمنا بتضمين الكلاس from ParentClass import ParentClass # ParentClass يرث من الكلاس ChildClass هنا قمنا بإنشاء كلاس إسمه class ChildClass(ParentClass): # ParentClass لأن هذه الدالة كانت معرفة كدالة مجرّدة في الكلاس m2() للدالة Override هنا فعلنا def m2(self): print('m2: Its content is written by ChildClass') # ParentClass لأن هذه الدالة كانت معرفة كدالة مجرّدة في الكلاس m3() للدالة Override هنا فعلنا def m3(self): super().m3() # و بعدها قمنا بإضافة أمر طباعة ParentClass الموجودة في الكلاس m3() لاحظ أننا قمنا باستدعاء الدالة print('m3: ChildClass add his own code too')
Test.py
# حتى نستطيع إنشاء كائن منه ChildClass هنا قمنا بتضمين الكلاس
from ChildClass import ChildClass
# obj إسمه ChildClass هنا قمنا بإنشاء كائن من الكلاس
obj = ChildClass()
# obj هنا قمنا باستدعاء الدوال الثلاثة الموجودة في الكائن
obj.m1()
obj.m2()
obj.m3()
# حتى نستطيع إنشاء كائن منه ChildClass هنا قمنا بتضمين الكلاس from ChildClass import ChildClass # obj إسمه ChildClass هنا قمنا بإنشاء كائن من الكلاس obj = ChildClass() # obj هنا قمنا باستدعاء الدوال الثلاثة الموجودة في الكائن obj.m1() obj.m2() obj.m3()

نتيجة تشغيل الملف Test.

m1: Normal method defined by ParentClass
m2: Its content is written by ChildClass
m3: Default content is written by ParentClass
m3: ChildClass add his own code too

أمثلة تطبيقية على التجريد

وضعنا هنا مثال بسيط حول كلاس مجرد يرث من كلاس مجرد.

شاهد المثال

وضعنا هنا مثال مهم يوضح فائدة إنشاء كلاس مجرد.

شاهد المثال


سترى فائدة التجريد أيضاً في دروس متقدمة عندما تستخدم كلاسات جاهزة تتيح لك التعامل مع الشبكات ( Networks ), واجهات المستخدم ( GUI ) و قواعد البيانات ( DataBases ) بكل سهولة. و ستراها عندما تعمل على بناء مشاريع كبيرة حيث تجبرك على إستخدام هذا الأسلوب لتسهيل العمل في المشروع.