البرمجة

البرمجة الكائنية في بايثون

جدول المحتوى

البرمجة كائنية التوجه (Object Oriented Programming) في بايثون – الجزء الثاني

تُعد البرمجة كائنية التوجه (Object Oriented Programming أو OOP) من أهم المفاهيم البرمجية التي ساهمت بشكل جذري في تطوير برمجيات معقدة بطريقة منظمة وقابلة لإعادة الاستخدام والصيانة. في الجزء الأول من المقال تناولنا التعريف الأساسي للبرمجة كائنية التوجه في لغة بايثون، والحديث عن الكائنات (Objects) والفئات (Classes) كمكونات أساسية، إضافة إلى شرح مفهوم الخصائص (Attributes) والطرق (Methods). في هذا الجزء الثاني سنغوص بعمق أكبر في مفاهيم متقدمة ومهمة داخل البرمجة كائنية التوجه في بايثون، وسنوضح كيفية الاستفادة منها لبناء تطبيقات برمجية قوية ومرنة.


1. الوراثة (Inheritance) في بايثون

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

كيف تعمل الوراثة؟

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

مثال عملي للوراثة في بايثون:

python
class Animal: def __init__(self, name): self.name = name def speak(self): return "Some generic sound" class Dog(Animal): def speak(self): return "Woof!" class Cat(Animal): def speak(self): return "Meow!"

في المثال السابق، الفئة Animal تمثل الفئة الأساسية، بينما Dog و Cat هما فئتان فرعيتان ترثان من Animal. كل فئة فرعية تعيد تعريف (Override) طريقة speak الخاصة بها، مما يسمح بتخصيص السلوك.


2. التعددية الشكلية (Polymorphism)

التعددية الشكلية تعني أن نفس العملية أو الدالة يمكن أن تعمل على كائنات من أنواع مختلفة بطريقة مناسبة لكل نوع. في بايثون، يتم تحقيق التعددية الشكلية عادة من خلال الوراثة وإعادة تعريف الطرق.

تطبيق التعددية الشكلية:

يمكن استدعاء نفس الطريقة speak على كائنات مختلفة (مثل كلب أو قطة) وستعمل كل منها بطريقتها الخاصة.

python
def animal_sound(animal): print(animal.speak()) dog = Dog("Buddy") cat = Cat("Whiskers") animal_sound(dog) # يطبع "Woof!" animal_sound(cat) # يطبع "Meow!"

الوظيفة animal_sound تتعامل مع أي كائن من النوع Animal أو المشتق منه، مما يجعل الكود أكثر مرونة وقابلية للتوسع.


3. التجريد (Abstraction)

التجريد هو إخفاء التفاصيل الداخلية المعقدة للكائن، وإظهار واجهة بسيطة للتعامل معه. في بايثون، يمكن تحقيق ذلك عبر الفئات المجردة (Abstract Classes) والطرق المجردة (Abstract Methods) باستخدام مكتبة abc.

الفئات والطرق المجردة:

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

مثال على استخدام الفئات المجردة:

python
from abc import ABC, abstractmethod class Shape(ABC): @abstractmethod def area(self): pass @abstractmethod def perimeter(self): pass class Rectangle(Shape): def __init__(self, width, height): self.width = width self.height = height def area(self): return self.width * self.height def perimeter(self): return 2 * (self.width + self.height)

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


4. التغليف (Encapsulation)

التغليف هو عملية حماية بيانات الكائن من التلاعب الخارجي غير المصرح به، وإخفاء التفاصيل الداخلية للكائن، مع توفير واجهات آمنة للتفاعل معها.

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

  • الخاصية التي تبدأ بـ _ تعتبر “محمية” وليست للاستخدام الخارجي بشكل مباشر.

  • الخاصية التي تبدأ بـ __ (double underscore) يتم تغيير اسمها داخليًا (Name Mangling) لجعل الوصول إليها أكثر صعوبة.

مثال على التغليف:

python
class Account: def __init__(self, owner, balance): self.owner = owner self.__balance = balance # خاص def deposit(self, amount): if amount > 0: self.__balance += amount def withdraw(self, amount): if 0 < amount <= self.__balance: self.__balance -= amount def get_balance(self): return self.__balance

في هذا المثال، الرصيد __balance مغلف ولا يمكن التلاعب به مباشرة من خارج الكائن. يتم تعديل الرصيد فقط من خلال الطرق deposit و withdraw التي تتحكم بالعمليات.


5. خصائص (Properties) في بايثون

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

تستخدم الخاصية @property لتعريف طريقة تُعامل كخاصية، مما يسمح بالتحكم في وصول وتعديل الخصائص بطريقة سلسة.

مثال على الخصائص:

python
class Celsius: def __init__(self, temperature=0): self._temperature = temperature @property def temperature(self): return self._temperature @temperature.setter def temperature(self, value): if value < -273.15: raise ValueError("درجة الحرارة لا يمكن أن تكون أقل من الصفر المطلق") self._temperature = value

في المثال أعلاه، temperature تُعامل كخاصية، مع حماية تحقق الشروط عند تعيين القيمة.


6. الطرق الخاصة والسحرية (Magic and Special Methods)

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

أهم الطرق السحرية:

  • __init__: المُهيئ، يتم استدعاؤه عند إنشاء كائن.

  • __str__: لتحويل الكائن إلى تمثيل نصي مناسب للعرض.

  • __repr__: تمثيل رسمي للكائن يستخدم عادة لأغراض التصحيح.

  • __add__: لتعريف سلوك الجمع بين كائنات.

  • __len__: تعيد طول الكائن.

  • __eq__: لتعريف مقارنة المساواة بين كائنات.

مثال على استخدام بعض الطرق السحرية:

python
class Point: def __init__(self, x, y): self.x = x self.y = y def __str__(self): return f"Point({self.x}, {self.y})" def __add__(self, other): return Point(self.x + other.x, self.y + other.y) def __eq__(self, other): return self.x == other.x and self.y == other.y

7. إدارة الموارد باستخدام with و Context Managers

تُستخدم إدارة الموارد للتعامل مع فتح وإغلاق الملفات أو قواعد البيانات وغيرها بطريقة منظمة وآمنة. في البرمجة كائنية التوجه، يمكن تعريف ما يُعرف بـ Context Managers للتحكم في دخول وخروج السياق (مثل فتح ملف ثم إغلاقه تلقائيًا).

يمكن تحقيق ذلك عبر تعريف طريقتين خاصتين هما:

  • __enter__: يتم استدعاؤها عند الدخول إلى كتلة with.

  • __exit__: تُستدعى عند الخروج من الكتلة، حتى في حال حدوث استثناء.

مثال على Context Manager:

python
class FileOpener: def __init__(self, filename, mode): self.file = open(filename, mode) def __enter__(self): return self.file def __exit__(self, exc_type, exc_val, exc_tb): self.file.close() with FileOpener('test.txt', 'w') as f: f.write('Hello, world!')

8. الوراثة المتعددة (Multiple Inheritance)

بايثون تدعم الوراثة من أكثر من فئة أصلية واحدة، مما يتيح مرونة أكبر في تصميم البرمجيات. ولكنها تتطلب فهمًا دقيقًا لترتيب البحث عن الطرق (Method Resolution Order – MRO) لتجنب التضارب.

مثال للوراثة المتعددة:

python
class Flyer: def fly(self): return "Flying" class Swimmer: def swim(self): return "Swimming" class Duck(Flyer, Swimmer): pass d = Duck() print(d.fly()) # Flying print(d.swim()) # Swimming

9. التعديل على الفئات (Class Decorators) والميتابرنامجينغ

بايثون توفر إمكانيات متقدمة لتعديل سلوك الفئات أثناء تعريفها باستخدام الديكوراتور (Decorators)، أو حتى استخدام metaclasses لتغيير آلية إنشاء الفئات.

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

يمكن استخدام ديكوراتور لتعزيز أو تعديل الفئة بدون تغيير كودها الأصلي.

python
def decorator(cls): cls.extra_method = lambda self: "Extra method added" return cls @decorator class MyClass: pass obj = MyClass() print(obj.extra_method()) # Extra method added

الميتابرنامجينغ (Metaprogramming)

الميتابرنامجينغ هو كتابة برامج تتعامل مع كود البرمجة ذاته، من خلال الميتاكلاسات التي تتحكم في إنشاء الفئات.

python
class Meta(type): def __new__(cls, name, bases, attrs): attrs['class_name'] = name return super().__new__(cls, name, bases, attrs) class MyClass(metaclass=Meta): pass print(MyClass.class_name) # MyClass

10. الأداء والتنظيم في البرمجة كائنية التوجه باستخدام بايثون

على الرغم من مزايا OOP، إلا أن الإفراط في استخدام الكائنات يمكن أن يؤدي إلى زيادة استهلاك الموارد وتأخير التنفيذ، لذا يجب على المبرمج اختيار التوازن المناسب بين البرمجة كائنية التوجه والأساليب الأخرى (مثل البرمجة الإجرائية).

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


11. مقارنة بين البرمجة كائنية التوجه والأساليب الأخرى في بايثون

بايثون تدعم البرمجة الإجرائية (Procedural)، الوظيفية (Functional)، وكائنية التوجه (OOP)، ولكل منها مكانه حسب طبيعة المشروع.

  • البرمجة الإجرائية تركز على الوظائف وترتيبها.

  • البرمجة الوظيفية تعتمد على استخدام الدوال ككائنات من الدرجة الأولى.

  • البرمجة كائنية التوجه تُركز على نمذجة البيانات كسلسلة من الكائنات والتفاعل بينها.

باستخدام OOP يمكن إدارة المشاريع الكبيرة والمعقدة بطريقة أكثر فعالية وتنظيمًا.


12. تلخيص لأهم مفاهيم الجزء الثاني في البرمجة كائنية التوجه في بايثون

  • الوراثة تسمح بإعادة استخدام الكود وتوسيع الفئات.

  • التعددية الشكلية تحقق مرونة عالية في التعامل مع أنواع مختلفة من الكائنات.

  • التجريد يُخفي التعقيدات ويحدد واجهات واضحة.

  • التغليف يحمي بيانات الكائن ويقلل من الأخطاء.

  • الخصائص تسمح بالتحكم في الوصول إلى السمات.

  • الطرق السحرية تتيح تعديل سلوك الكائنات في العمليات الأساسية.

  • إدارة الموارد باستخدام Context Managers يضمن التعامل السليم مع الموارد.

  • الوراثة المتعددة تزيد من مرونة التصميم.

  • ديكوراتور الفئات والميتابرنامجينغ يسمحان بتعديل الكود بشكل ديناميكي.

  • التوازن في استخدام OOP مهم لتحسين الأداء والتنظيم.


جدول توضيحي لبعض الطرق الخاصة (Special Methods) في بايثون

الطريقة الخاصة الوصف الاستخدام العملي
__init__ تهيئة الكائن عند إنشائه تعيين القيم الأولية للخصائص
__str__ تمثيل نصي للكائن الطباعة وعرض الكائن بطريقة مفهومة
__repr__ تمثيل رسمي للكائن التصحيح وعرض الكائن
__add__ الجمع بين كائنين دعم عملية الجمع (+)
__eq__ مقارنة المساواة بين كائنين استخدام عامل المساواة (==)
__len__ تعيد طول الكائن استخدام دالة len()
__enter__ و __exit__ دعم سياقات with إدارة الموارد مثل الملفات

المصادر والمراجع

  1. Python Documentation – Classes

    https://docs.python.org/3/tutorial/classes.html

  2. Real Python – Object-Oriented Programming (OOP) in Python 3

    https://realpython.com/python3-object-oriented-programming/


هذا المقال يقدم نظرة شاملة ومتقدمة عن البرمجة كائنية التوجه في بايثون، ويساعد في بناء قاعدة معرفية قوية يمكن من خلالها تطوير برمجيات عالية الجودة.