شرح OOP في Python يبدأ بكلاس يصف نوعًا من الكائنات، ثم نسخة فعلية تحتفظ ببياناتها. سنستخدم Person باسم وعمر وعناوين، ونضيف دوال لتغيير المعلومات وفق قواعد واضحة. لا تعني البرمجة الكائنية وضع كل شيء في كلاس؛ فائدتها تظهر عندما ترتبط حالة الكائن بالعمليات التي تؤثر فيها. بدل تخزين العمر في متغيرات مختلفة بلا تنظيم، يصبح للكائن مسار واحد لقراءة القيمة وتحديثها.
التجهيز والتشغيل
استخدم Python 3.9 أو أحدث واحفظ المثال في ملف مستقل خارج مجلد مكتبات Python.
python lesson_25629.pyالفرق بين خصائص الفئة والنسخة
الخصائص التي تعين عبر self داخل __init__ تخص النسخة التي تنشئها. أما القائمة المعرفة على مستوى الكلاس فقد تتشاركها النسخ إذا استُخدمت دون إنشاء قائمة جديدة لكل كائن. ينشئ المثال __addresses داخل المنشئ حتى لا تنتقل عناوين شخص إلى آخر بالخطأ. ويستخدم first_name وlast_name بأسماء متناسقة؛ تعيين gender داخل first_name كما يحدث في نسخ تعليمية قديمة يستبدل الاسم بدل إضافة خاصية أخرى.
التحقق من العمر باستخدام property
نعرّف age كخاصية لها getter وsetter. يمر الإسناد person.age = 23 عبر الفحص ثم يخزن القيمة في _age، فلا نخلط بين __age وage ونظن أننا نحدث المتغير نفسه. نرفض النصوص والقيم السالبة وbool لأن True يعد نوعًا فرعيًا من int في Python لكن ليس عمرًا مناسبًا في عقد المثال. العمر صفر مسموح. وعند رفض قيمة جديدة تبقى القيمة السابقة الصحيحة دون تغيير.
المثال البرمجي الكامل
class Person:
def __init__(self, first_name, last_name, age):
self.first_name, self.last_name = first_name, last_name
self.age = age
self.__addresses = []
@property
def age(self):
return self._age
@age.setter
def age(self, value):
if type(value) is not int:
raise TypeError("Age must be an integer")
if value < 0:
raise ValueError("Age cannot be negative")
self._age = value
@property
def full_name(self):
return f"{self.first_name} {self.last_name}"
def get_addresses(self):
return self.__addresses.copy()
def add_address(self, address):
address = address.strip().title()
if not address:
raise ValueError("Address cannot be blank")
if address not in self.__addresses:
self.__addresses.append(address)
def remove_address(self, address):
address = address.strip().title()
if address in self.__addresses:
self.__addresses.remove(address)
return True
return False
if __name__ == "__main__":
person = Person("Ali", "Hassan", 22)
person.age = 23
person.add_address("cairo")
copied = person.get_addresses()
copied.append("Not added to the person")
print(person.full_name, person.age, person.get_addresses())
التغليف لا يعني تشفير البيانات
الشرطة السفلية في _age اتفاق على الاستخدام الداخلي، والشرطتان في __addresses تطبقان تعديل اسم الخاصية داخل الفئة. لا تحول هذه الأسماء البيانات إلى أسرار محمية من شخص يشغل Python على الجهاز. الغرض توضيح واجهة الاستخدام وتقليل التعديلات غير المقصودة. إذا احتجت حماية بيانات فعلية فذلك يتعلق بصلاحيات التطبيق والتخزين والمصادقة، وليس بمجرد إضافة شرطتين قبل اسم المتغير.
نسخة العناوين ومنع التغيير الخارجي
ترجع get_addresses نسخة من القائمة. عندما يضيف المستدعي عنصرًا إلى النسخة، لا يتغير كائن Person. هذا دفاع بسيط مناسب لقائمة نصوص؛ لو كانت العناصر قواميس متداخلة فنسخ القائمة سطحي ولا ينسخ محتويات كل قاموس. تنظم add_address الفراغات وحالة الحروف الإنجليزية وتمنع التكرار المطابق بعد التنظيم، بينما تعيد remove_address قيمة منطقية توضح هل حُذف عنصر موجود بالفعل.
تشغيل ومقارنة نسختين
احفظ المثال ثم شغله لتظهر معلومات الشخص والعناوين. أنشئ شخصًا ثانيًا وأضف عنوانًا للأول، ثم تحقق أن الثاني لم يتغير. جرّب person.age = "24" وبعد رفضها اطبع العمر لتتأكد من بقاء العدد السابق. full_name خاصية محسوبة من الاسمين؛ لا تحتاج تخزين نسخة ثالثة قد تصبح قديمة عند تعديل الاسم. تمييز البيانات المخزنة عن القيم المحسوبة يقلل التناقض داخل الكائن.
متى أستخدم دالة ومتى خاصية؟
تصلح property لقيمة تبدو كجزء من حالة الكائن ويمكن قراءتها بصورة بسيطة، مثل العمر أو الاسم الكامل. أما عملية ذات آثار واضحة كإضافة عنوان أو إزالته فدالة مسماة تكون أوضح. لا تضع عملًا بطيئًا أو اتصالًا بالشبكة داخل getter دون أن يتوقع المستدعي ذلك. وعندما يبدأ المنشئ في استقبال عشرات القيم، راجع تقسيم المسؤوليات بدل جعل Person مسؤولة عن كل تفاصيل النظام.
تمرين للتأكد من فهم التغليف
أضف فحصًا يمنع الاسم الأول الفارغ، ثم قرر هل تريد السماح بتغيير الاسمين بعد الإنشاء. اختبر عنوانًا فارغًا وعنوانًا بحروف مختلفة وعنوانًا غير موجود عند الإزالة. اكتب اختبارًا يعيد نسخة العناوين مرتين ويتأكد من استقلال القائمتين. بعد استيعاب هذا الدرس انتقل إلى الوراثة وsuper والدوال السحرية، لأن صحة واجهة الكائن الأساسية أهم من إضافة معاملات مقارنة إلى حالة غير متناسقة.
المراجع
الصور والفيديو من الشرح السابق
الكود النصي أعلاه هو النسخة المصححة؛ قد تختلف المواد المرئية السابقة في أسماء المتغيرات أو طريقة التشغيل.







