0%
البرمجة كائنية التوجه في بايثون

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

نظّم شيفرتك باستخدام الكائنات والأصناف

10-15 دقيقة

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

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

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

قبل الغوص في التفاصيل، من المهم أن نفهم سبب شعبية هذا النموذج الكبيرة:

  1. التنظيم: تتيح لك البرمجة كائنية التوجه تنظيم شيفرتك بشكل أكثر بنية وأكثر نمطية (modular).
  2. إعادة الاستخدام: تسهّل إعادة استخدام الشيفرة بفضل الوراثة والتركيب.
  3. سهولة الصيانة: الشيفرة المنظّمة جيدًا في شكل كائنات تكون عمومًا أسهل في الصيانة والتطوير.
  4. التغليف: تتيح البرمجة كائنية التوجه إخفاء التعقيد وحماية البيانات بفضل التغليف.

الأصناف والكائنات

المفهومان الأساسيان في البرمجة كائنية التوجه هما الأصناف (classes) والكائنات (objects).

الأصناف

الصنف هو قالب أو مخطط لإنشاء الكائنات. وهو يحدد السمات (المتغيرات) والطرائق (الدوال) التي ستمتلكها الكائنات.

إليك كيفية تعريف صنف بسيط في بايثون:

class Personne:
    def __init__(self, nom, age):
        self.nom = nom
        self.age = age
    
    def saluer(self):
        return f"Bonjour, je m'appelle {self.nom} et j'ai {self.age} ans."

في هذا المثال:

  • Personne هو اسم الصنف.
  • __init__ هي طريقة خاصة (دالة بانية) تقوم بتهيئة كائن جديد.
  • self يشير إلى نسخة الكائن الحالية.
  • nom وage هما سمتان.
  • saluer هي طريقة.

الكائنات

الكائن هو نسخة (instance) من صنف. لإنشاء كائن، تستدعي الصنف كما تستدعي الدالة:

personne1 = Personne("Alice", 30)
personne2 = Personne("Bob", 25)

print(personne1.saluer())  # Affiche: Bonjour, je m'appelle Alice et j'ai 30 ans.
print(personne2.saluer())  # Affiche: Bonjour, je m'appelle Bob et j'ai 25 ans.

الكائنان personne1 وpersonne2 نسختان مستقلتان من الصنف Personne، ولكل منهما قيم سماته الخاصة.

الطرائق الخاصة

توفّر بايثون عدة طرائق خاصة (تُسمّى أيضًا الطرائق السحرية أو طرائق dunder اختصارًا لـ “double underscore”) تتيح تخصيص سلوك الكائنات.

class Livre:
    def __init__(self, titre, auteur, pages):
        self.titre = titre
        self.auteur = auteur
        self.pages = pages
        self.page_actuelle = 0
    
    def __str__(self):
        """Définit comment l'objet est représenté sous forme de chaîne."""
        return f"{self.titre} par {self.auteur}"
    
    def __len__(self):
        """Définit le comportement quand la fonction len() est appliquée à l'objet."""
        return self.pages
    
    def __del__(self):
        """Méthode appelée lorsque l'objet est supprimé."""
        print(f"Le livre {self.titre} a été fermé.")

livre = Livre("Python Facile", "J. Dupont", 200)
print(livre)           # Utilise __str__
print(len(livre))      # Utilise __len__
del livre              # Déclenche __del__

الوراثة

تتيح الوراثة لصنف أن يرث السمات والطرائق من صنف آخر. وهي مفهوم أساسي لتعزيز إعادة استخدام الشيفرة.

class Animal:
    def __init__(self, nom):
        self.nom = nom
    
    def parler(self):
        pass  # Méthode à surcharger dans les classes dérivées

class Chien(Animal):
    def parler(self):
        return f"{self.nom} dit Woof!"

class Chat(Animal):
    def parler(self):
        return f"{self.nom} dit Meow!"

animaux = [Chien("Rex"), Chat("Misty")]
for animal in animaux:
    print(animal.parler())

في هذا المثال:

  • Animal هو الصنف الأساسي (أو الصنف الأب).
  • Chien وChat صنفان مشتقان (أو صنفان ابنان) يرثان من Animal.
  • الطريقة parler يُعاد تعريفها (override) في كل صنف مشتق.

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

على عكس بعض لغات البرمجة، تدعم بايثون الوراثة المتعددة، مما يتيح لصنف أن يرث من عدة أصناف أب.

class A:
    def methode_a(self):
        return "Méthode de A"

class B:
    def methode_b(self):
        return "Méthode de B"

class C(A, B):  # Hérite de A et B
    def methode_c(self):
        return "Méthode de C"

objet = C()
print(objet.methode_a())  # Hérité de A
print(objet.methode_b())  # Hérité de B
print(objet.methode_c())  # Défini dans C

التغليف

التغليف هو مفهوم تجميع البيانات والطرائق التي تعمل عليها، وتقييد الوصول المباشر إلى متغيرات الكائن.

في بايثون، يتحقق التغليف بالاصطلاح (convention) أكثر منه بالفرض الصارم:

class CompteBancaire:
    def __init__(self, solde_initial):
        self._solde = solde_initial  # Convention: attribut protégé (single underscore)
        self.__compte_id = "123456"  # Convention: attribut privé (double underscore)
    
    def deposer(self, montant):
        self._solde += montant
    
    def retirer(self, montant):
        if montant <= self._solde:
            self._solde -= montant
            return True
        return False
    
    def get_solde(self):
        return self._solde

compte = CompteBancaire(1000)
compte.deposer(500)
print(compte.get_solde())  # 1500
print(compte._solde)       # Accessible, mais par convention, ne devrait pas être accédé directement
# print(compte.__compte_id)  # Erreur: renommage par "name mangling"
print(compte._CompteBancaire__compte_id)  # Accessible via mangling

في بايثون:

  • السمة التي تبدأ بشرطة سفلية واحدة (_solde) تشير إلى أنها محمية (اصطلاح فقط، ولا يُفرض).
  • السمة التي تبدأ بشرطتين سفليتين (__compte_id) تخضع لما يسمى “name mangling” (إعادة التسمية)، مما يجعل الوصول إليها عن طريق الخطأ أصعب، لكنها ليست خاصة فعليًا.

تعدد الأشكال

يتيح تعدد الأشكال (polymorphism) معاملة كائنات من أصناف مختلفة على أنها كائنات من صنف مشترك. وفي بايثون، تعدد الأشكال جزء أصيل من اللغة بفضل الـ duck typing.

def faire_parler(animal):
    print(animal.parler())

chien = Chien("Rex")
chat = Chat("Misty")

faire_parler(chien)  # Rex dit Woof!
faire_parler(chat)   # Misty dit Meow!

تعمل الدالة faire_parler مع أي كائن يملك الطريقة parler، دون الاهتمام بصنفه الفعلي.

الخصائص

تتيح الخصائص (properties) التحكم في الوصول إلى سمات الصنف مع الحفاظ على واجهة نظيفة.

class Temperature:
    def __init__(self, celsius=0):
        self._celsius = celsius
    
    @property
    def celsius(self):
        return self._celsius
    
    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("La température ne peut pas être inférieure au zéro absolu.")
        self._celsius = value
    
    @property
    def fahrenheit(self):
        return self._celsius * 9/5 + 32
    
    @fahrenheit.setter
    def fahrenheit(self, value):
        self.celsius = (value - 32) * 5/9

temp = Temperature()
temp.celsius = 25
print(f"Celsius: {temp.celsius}°C, Fahrenheit: {temp.fahrenheit}°F")

temp.fahrenheit = 77
print(f"Celsius: {temp.celsius}°C, Fahrenheit: {temp.fahrenheit}°F")

طرائق الصنف وسماته

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

class Voiture:
    # Attribut de classe
    nombre_de_voitures = 0
    
    def __init__(self, marque, modele):
        self.marque = marque
        self.modele = modele
        # Incrémenter l'attribut de classe
        Voiture.nombre_de_voitures += 1
    
    @classmethod
    def get_nombre_de_voitures(cls):
        return cls.nombre_de_voitures
    
    @staticmethod
    def est_electrique(marque, modele):
        # Une méthode statique qui ne dépend pas de l'état de l'instance
        # Liste fictive de voitures électriques
        voitures_electriques = [("Tesla", "Model 3"), ("Nissan", "Leaf")]
        return (marque, modele) in voitures_electriques

voiture1 = Voiture("Toyota", "Corolla")
voiture2 = Voiture("Honda", "Civic")

print(Voiture.get_nombre_de_voitures())  # 2
print(Voiture.est_electrique("Tesla", "Model 3"))  # True

الخاتمة

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

في هذا الدرس، تناولنا المفاهيم الأساسية للبرمجة كائنية التوجه في بايثون، بما فيها الأصناف والكائنات والوراثة وتعدد الأشكال والتغليف. لكن هذه ليست سوى البداية! فهناك العديد من المفاهيم المتقدمة وأنماط التصميم (design patterns) الأخرى التي يمكن أن تساعدك على الاستفادة القصوى من هذا النموذج.

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

التعليقات

التعليقات مدعومة عبر GitHub Discussions

سجّل الدخول باستخدام GitHub للمشاركة في النقاش

تم نسخ الرابط!