بايثون المتوسط: البرمجة الشيئية في الممارسة - الكود والأوامر التي تهم حقاً
بايثون المتوسط POO: الأساسيات في مقال واحد — كود حقيقي، مخططات وخطوات ملموسة، مقتطفات من دورة مكونة من 36 درساً.
لا نظرية طويلة هنا: نفتح الطرفية ونمارس. إليك أساسيات بايثون المتوسط POO، مستخرجة مباشرة من دورة كاملة تضم 36 درسًا — مع كود حقيقي يمكنك نسخه ولصقه الآن.
- مقدمة وتثبيت
- تذكير بايثون
- دوال متقدمة ولمدا
- الفئات والكائنات
- الوراثة وتعدد الأشكال
التغليف، الخصائص والمُعيّنات
الأهداف التعليمية
_x و__x، وتحويل سمة إلى property لإضافة التحقق، ومعرفة متى يتم ذلك.ما هو التغليف؟
يتكون التغليف من إخفاء التفاصيل الداخلية لفئة وعرض واجهة محكومة فقط.
اصطلاحات بايثون
بايثون لا يفرض السرية (على عكس جافا). يستخدم اصطلاحات مبنية على الاسم.
| الاصطلاح | المعنى | التأثير الفعلي |
|---|---|---|
nom | عام | وصول حر، جزء من الـAPI |
_nom | محمي (اصطلاح) | "لا تلمسه إلا إذا كنت تعرف ما تفعله" |
__nom | خاص (name mangling) | يُعاد تسميته إلى _NomClasse__nom |
nom_ | تجنب التصادم مع كلمة مفتاحية | مثال: class_ بدلاً من class |
class CompteBancaire:
def __init__(self, titulaire, solde):
self.titulaire = titulaire # عام
self._solde = solde # اصطلاح: لا تلمسه
self.__pin = "1234" # خاص (name mangling)
c = CompteBancaire("Alice", 1000)
print(c.titulaire) # OK
print(c._solde) # يمكن الوصول إليه لكنه غير مستحسن
# print(c.__pin) # AttributeError !
print(c._CompteBancaire__pin) # يمكن الوصول إليه بالاسم المعدل__ ليس أمانًا — إنه آلية لتجنب التصادمات العرضية في الوراثة. لأمان حقيقي، استخدم أذونات على مستوى النظام.المشكلة بدون تغليف
class Temperature:
def __init__(self, celsius):
self.celsius = celsius
t = Temperature(25)
t.celsius = -500 # غير منطقي!
print(t.celsius) # -500لا يوجد تحقق. القيمة -500 مستحيلة (الصفر المطلق = -273.15) لكن بايثون يقبلها.
@property: تحويل سمة إلى طريقة
يجعل @property استدعاءً مثل obj.attribut ينفذ في الواقع طريقة، دون تغيير صيغة الاستخدام.
class Temperature:
def __init__(self, celsius):
self._celsius = celsius
@property
def celsius(self):
return self._celsius
@celsius.setter
def celsius(self, valeur):
if valeur < -273.15:
raise ValueError("تحت الصفر المطلق، مستحيل")
self._celsius = valeur
t = Temperature(25)
print(t.celsius) # 25 (يستدعي الـgetter)
t.celsius = 30 # يستدعي الـsetter، OK
t.celsius = -300 # ValueError !t.celsius (البسيطة) لكن تضيف تحكمًا غير مرئي. لا يحتاج كود المستخدم إلى أي تغيير.Property للقراءة فقط
لسمة محسوبة (مشتقة من غيرها) لا يجب تعديلها مباشرة.
class Cercle:
def __init__(self, rayon):
self.rayon = rayon
@property
def diametre(self):
return self.rayon * 2
@property
def aire(self):
from math import pi
return pi * self.rayon ** 2
c = Cercle(5)
print(c.diametre) # 10
print(c.aire) # 78.539...
# c.aire = 100 # AttributeError : لا يوجد setterProperty كاملة مع getter وsetter وdeleter
class Personne:
def __init__(self, nom):
self._nom = nom
@property
def nom(self):
return self._nom
@nom.setter
def nom(self, valeur):
if not isinstance(valeur, str) or len(valeur) < 2:
raise ValueError("اسم غير صالح")
self._nom = valeur.title() # تطبيع
@nom.deleter
def nom(self):
print("حذف الاسم")
self._nom = None
p = Personne("alice")
print(p.nom) # Alice (مطبّع)
p.nom = "bob"
print(p.nom) # Bob
del p.nom # حذف الاسمحالة عملية: CompteBancaire مع التحقق
class CompteBancaire:
def __init__(self, titulaire, solde=0):
self.titulaire = titulaire
self._solde = 0
self.solde = solde # يمر عبر الـsetter!
@property
def solde(self):
return self._solde
@solde.setter
def solde(self, valeur):
if valeur < 0:
raise ValueError("رصيد سالب ممنوع")
self._solde = valeur
def deposer(self, montant):
if montant <= 0:
raise ValueError("يجب أن يكون المبلغ موجبًا")
self.solde += montant # يمر عبر الـsetter
def retirer(self, montant):
if montant > self._solde:
raise ValueError("رصيد غير كافٍ")
self.solde -= montant
c = CompteBancaire("Alice", 1000)
c.deposer(500)
print(c.solde) # 1500
# c.solde = -100 # ValueErrorالوراثة البسيطة
الأهداف التعليمية
super().المفهوم
تسمح الوراثة بإنشاء فئة متخصصة انطلاقًا من فئة عامة. تحصل الفئة الابنة على كل ما تقدمه الفئة الأم، ثم تضيف أو تعدل.
Chien هو Animal.المثال الأول
class Animal:
def __init__(self, nom, age):
self.nom = nom
self.age = age
def manger(self):
print(f"{self.nom} mange")
def dormir(self):
print(f"{self.nom} dort")
class Chien(Animal):
def aboyer(self):
print(f"{self.nom} : Wouaf !")
rex = Chien("Rex", 5)
rex.manger() # موروث من Animal
rex.dormir() # موروث من Animal
rex.aboyer() # خاص بـChien
print(rex.age) # موروثChien لا يعرف __init__: يستخدم بايثون تلقائيًا ذلك الخاص بـAnimal.
تجاوز (override) طريقة
يمكن للفئة الابنة إعادة تعريف طريقة الأم لتكييف سلوكها.
class Animal:
def parler(self):
print("Bruit générique d’animal")
class Chien(Animal):
def parler(self):
print("Wouaf !")
class Chat(Animal):
def parler(self):
print("Miaou")
for a in [Chien(), Chat(), Animal()]:
a.parler()
# Wouaf !
# Miaou
# Bruit générique d’animala.parler() ينتج نتيجة مختلفة حسب الفئة الحقيقية لـa. إنه أحد أعمدة POO الأربعة.super(): استدعاء الطريقة الأبوية
عند تجاوز طريقة، غالبًا ما نريد إكمال السلوك الأبوي بدلًا من استبداله.
class Animal:
def __init__(self, nom, age):
self.nom = nom
self.age = age
def description(self):
return f"{self.nom}, {self.age} ans"
class Chien(Animal):
def __init__(self, nom, age, race):
super().__init__(nom, age) # يستدعي Animal.__init__
self.race = race
def description(self):
base = super().description() # يستدعي Animal.description
return f"{base}, race {self.race}"
rex = Chien("Rex", 5, "Labrador")
print(rex.description()) # Rex, 5 ans, race Labrador__init__ خاصًا بها، يجب استدعاء super().__init__(...) لتهيئة سمات الأم. النسيان = أخطاء مضمونة.التحقق من القرابة: isinstance وissubclass
rex = Chien("Rex", 5, "Labrador")
print(isinstance(rex, Chien)) # True
print(isinstance(rex, Animal)) # True (وراثة)
print(isinstance(rex, Chat)) # False
print(issubclass(Chien, Animal)) # True
print(issubclass(Animal, Chien)) # Falseisinstance(x, Animal) بدلًا من type(x) == Animal. الشكل الأول يحترم الوراثة.متى نستخدم الوراثة؟
| العلاقة | وراثة؟ |
|---|---|
| Chien هو Animal | نعم |
| Roman هو Livre | نعم |
| Voiture لديه Moteur | لا — تركيب |
| Bibliothèque تحتوي على Livres | لا — تركيب |
حالة حقيقية: تطبيق مكتبة
class Livre:
def __init__(self, titre, auteur, isbn):
self.titre = titre
self.auteur = auteur
self.isbn = isbn
self.disponible = True
def description(self):
return f"{self.titre} de {self.auteur}"
class Roman(Livre):
def __init__(self, titre, auteur, isbn, genre):
super().__init__(titre, auteur, isbn)
self.genre = genre
def description(self):
return f"{super().description()} -- roman {self.genre}"
class LivreNumerique(Livre):
def __init__(self, titre, auteur, isbn, format_fichier):
super().__init__(titre, auteur, isbn)
self.format_fichier = format_fichier
def telecharger(self):
print(f"Téléchargement de {self.titre}.{self.format_fichier}")
dune = Roman("Dune", "Herbert", "978...", "science-fiction")
ebook = LivreNumerique("1984", "Orwell", "978...", "epub")
print(dune.description()) # Dune de Herbert -- roman science-fiction
print(ebook.description()) # 1984 de Orwell
ebook.telecharger() # Téléchargement de 1984.epubالتسلسلات الهرمية الشائعة في بايثون
Lambda، map، filter، reduce
lambda) والدوال ذات الترتيب الأعلى (map، filter، reduce)، التي تسمح بتحويل وتصفية البيانات بطريقة موجزة جدًا.الأهداف التعليمية
lambda، وتختار بين map/filter وفهم القائمة حسب السياق.ما هي lambda؟
اللامدا هي دالة مجهولة (بلا اسم) تتسع في سطر واحد. تستخدم لعمليات قصيرة تُمرر كوسيط لدالة أخرى.
الصيغة
lambda parametres: expression
مقارنة
def doubler(x):
return x * 2
doubler_lambda = lambda x: x * 2
print(doubler(5)) # 10
print(doubler_lambda(5)) # 10def التقليدية تشبه كتابة وصفة باسم في كتاب. أما lambda فهي كتابة وصفة على ورقة لاصقة تعطيها فورًا لشخص ما.لامدا متعددة المعاملات
somme = lambda a, b: a + b print(somme(3, 4)) # 7 est_pair = lambda n: n % 2 == 0 print(est_pair(8)) # True
return صريح، ولا عدة أسطر. عند التعقيد استخدم def.map(): تحويل كل عنصر
map(fonction, iterable) يطبق الدالة على كل عنصر ويعيد مكررًا. غالبًا ما نلفه بـlist().
prix = [10, 25, 7, 50] prix_ttc = list(map(lambda p: p * 1.20, prix)) print(prix_ttc) # [12.0, 30.0, 8.4, 60.0] mots = ["python", "poo", "code"] majuscules = list(map(str.upper, mots)) print(majuscules) # ['PYTHON', 'POO', 'CODE']
مع عدة تسلسلات
a = [1, 2, 3] b = [10, 20, 30] sommes = list(map(lambda x, y: x + y, a, b)) print(sommes) # [11, 22, 33]
filter(): الاحتفاظ بما يجتاز الاختبار
notes = [12, 8, 15, 6, 18, 11] reussies = list(filter(lambda n: n >= 10, notes)) print(reussies) # [12, 15, 18, 11] mots = ["chat", "chien", "ours", "lion"] courts = list(filter(lambda m: len(m) <= 4, mots)) print(courts) # ['chat', 'ours', 'lion']
يغطي هذا المقال المقتطفات الأكثر فائدة — الدورة الكاملة بايثون المتوسط POO (11 فصلاً، 36 درسًا، تمارين مصححة ومشروع نهائي) تأخذك إلى النهاية.
./acceder-au-cours-complet دورة مجانية: إتقان Claude Codeالأسئلة الشائعة
كم من الوقت لتعلم بايثون المتوسط POO؟
هل هناك متطلبات مسبقة؟
من أين نبدأ عمليًا؟
📬 هل تريد تلقي هذا النوع من الأدلة كل أسبوع؟ اشترك مجانًا — كود حقيقي، بدون كلام فارغ.