الفصل العاشر: البرمجة كائنية التوجه (OOP) – بناء عوالم مصغرة في الكود
مقدمة الفصل
في الفصول السابقة، تعلمنا تنظيم الكود في دوال لتجميع المهام المتكررة. هذا الأسلوب ممتاز، لكن تخيل أنك تبني لعبة كبيرة. سيكون لديك لاعبون، ووحوش، وأدوات. كل “شيء” من هذه الأشياء له بياناته الخاصة (نقاط الصحة، القوة، الموقع) وأفعاله الخاصة (يتحرك، يهاجم، يستخدم أداة).
إذا حاولنا تمثيل ذلك بالدوال والمتغيرات فقط، سينتهي بنا الأمر مع مئات المتغيرات المنفصلة (player_health
, monster_health
, player_x_position
) ودوال لا حصر لها (move_player()
, move_monster()
). سيصبح الكود فوضويًا ومن الصعب جدًا تتبع أي بيانات تنتمي إلى أي فعل.
هنا يأتي دور البرمجة كائنية التوجه (Object-Oriented Programming - OOP). إنها ليست مجرد طريقة لكتابة الكود، بل هي طريقة تفكير تحاكي العالم الحقيقي. في هذا النمط، نفكر في برنامجنا كمجموعة من “الكائنات” (objects) المستقلة التي تتفاعل مع بعضها البعض. كل كائن هو حزمة متكاملة تحتوي على خصائصها (بياناتها) وسلوكياتها (وظائفها).
1. الفكرة الأساسية: من البيانات والدوال إلى الكائنات
لنفكر في مثال السيارة.
- خصائصها (بياناتها): لونها، موديلها، سرعتها الحالية.
- سلوكياتها (أفعالها): تتحرك، تتوقف، تسرّع.
في البرمجة كائنية التوجه، بدلاً من وجود متغيرات ودوال متناثرة، نقوم بإنشاء كائن سيارة. هذا الكائن “يعرف” لونه وموديله، و”يعرف كيف” يتحرك ويتوقف. كل ما يتعلق بالسيارة يتم تغليفه داخل هذه الوحدة المنطقية الواحدة.
القوة الحقيقية تظهر عندما ننشئ عدة كائنات: my_car
قد تكون سيارة تويوتا حمراء، و your_car
قد تكون سيارة فورد زرقاء. كل كائن يحتفظ ببياناته الخاصة بشكل مستقل عن الآخر.
2. المخطط الأساسي: الكلاس (Class)
قبل أن تتمكن شركة سيارات من بناء آلاف السيارات، فإنها تحتاج إلى مخطط تصميم (blueprint) واحد يصف كيفية بناء أي سيارة من هذا النوع. في OOP، هذا المخطط هو الكلاس (Class).
الكلاس (Class): هو القالب أو المخطط الذي نستخدمه لإنشاء الكائنات. إنه لا يمثل سيارة حقيقية، بل يصف ما هي الخصائص (Attributes) والسلوكيات (Methods) التي ستمتلكها أي سيارة يتم إنشاؤها منه.
الكائن (Object/Instance): هو النسخة الحقيقية التي يتم بناؤها من الكلاس. my_car
هي كائن أو نسخة (instance) من الكلاس Car
.
كيف نعرّف كلاسًا بسيطًا:
نستخدم الكلمة المفتاحية class
. جرت العادة أن تبدأ أسماء الكلاسات بحرف كبير.
# تعريف كلاس اسمه 'Car' ليكون بمثابة المخطط
class Car:
# pass هي كلمة مفتاحية لا تفعل شيئًا.
# نستخدمها هنا كمؤقت لأن بنية الكلاس لا يمكن أن تكون فارغة.
pass
3. بناء الكائن: المُنشِئ __init__
وكلمة self
السحرية
عندما نبني سيارة حقيقية من المخطط، نريد أن نحدد خصائصها الأولية (لونها، موديلها). لهذا نستخدم دالة خاصة جدًا داخل الكلاس.
الدوال السحرية (Dunder Methods)
في بايثون، أي دالة يبدأ اسمها وينتهي بشرطتين سفليتين مزدوجتين (مثل __init__
) هي دالة خاصة أو “سحرية”. هذه الدوال لا نستدعيها عادة بشكل مباشر، بل تستدعيها بايثون تلقائيًا عند وقوع أحداث معينة.
المُنشِئ __init__
الوصف:
تُسمى دالة __init__
بـ المُنشِئ (constructor). يتم استدعاؤها تلقائيًا في كل مرة يتم فيها إنشاء كائن جديد من الكلاس. وظيفتها هي تهيئة الخصائص الأولية للكائن.
فهم self
الوصف:
self
هو أهم مفهوم في هذا الفصل. إنه معامل إلزامي في كل دوال الكلاس، وهو يشير إلى الكائن نفسه الذي يتم العمل عليه.
كيف يعمل؟
عندما تكتب my_car = Car("Toyota", "Red")
، تقوم بايثون بالخطوات التالية خلف الكواليس:
- تنشئ كائنًا فارغًا في الذاكرة.
- تستدعي دالة
__init__
الخاصة بكلاسCar
. - تمرر هذا الكائن الفارغ الذي أنشأته تلقائيًا كأول وسيط للدالة، وهو ما نسميه
self
. لذلك، عندما تكتبself.brand = brand
داخل__init__
، فأنت تقول لبايثون: “خذ هذا الكائن الجديد الفارغ (self
) وأنشئ بداخله متغيرًا اسمهbrand
وخزن فيه القيمة التي تم تمريرها”.
class Car:
# دالة __init__ هي المُنشئ
def __init__(self, brand, model, color):
# الخصائص (Attributes) هي المتغيرات التي تنتمي للكائن
# نستخدم self لربط هذه الخصائص بالكائن الحالي
print(f"يتم الآن بناء سيارة جديدة...")
self.brand = brand
self.model = model
self.color = color
self.is_running = False # خاصية بقيمة افتراضية
# الآن، ننشئ كائنًا (نسخة) من كلاس السيارة
# هذا السطر يستدعي __init__ تلقائيًا
my_first_car = Car("Toyota", "Corolla", "Red")
# الوصول إلى الخصائص باستخدام النقطة
print(f"ماركة سيارتي هي: {my_first_car.brand}")
print(f"لونها هو: {my_first_car.color}")
4. السلوكيات: الدوال (Methods)
الدوال (Methods) هي ببساطة دوال يتم تعريفها داخل الكلاس لتمثل السلوكيات والأفعال التي يمكن للكائن القيام بها. الفرق الوحيد بينها وبين الدوال العادية هو أنها دائمًا تأخذ self
كأول معامل لها، مما يسمح لها بالوصول إلى خصائص وسلوكيات الكائن الأخرى وتعديلها.
class Car:
def __init__(self, brand, model):
self.brand = brand
self.model = model
self.is_running = False # السيارة متوقفة بشكل افتراضي
# دالة (method) لتشغيل المحرك
def start_engine(self):
if not self.is_running:
self.is_running = True
print(f"محرك السيارة {self.brand} {self.model} يعمل الآن.")
else:
print("المحرك يعمل بالفعل.")
# دالة لإيقاف المحرك
def stop_engine(self):
if self.is_running:
self.is_running = False
print(f"تم إيقاف محرك السيارة {self.brand} {self.model}.")
else:
print("المحرك متوقف بالفعل.")
# إنشاء كائن
my_car = Car("Ford", "Mustang")
# استدعاء الدوال على الكائن
my_car.start_engine()
my_car.start_engine() # محاولة التشغيل مرة أخرى
my_car.stop_engine()
الشرح:
عندما نستدعي my_car.start_engine()
، تقوم بايثون بتمرير الكائن my_car
تلقائيًا كوسيط self
للدالة. لهذا السبب، يمكن للدالة start_engine
الوصول إلى self.is_running
ومعرفة حالة محرك هذه السيارة تحديدًا وتغييرها.
5. خصائص الكلاس مقابل خصائص النسخة
حتى الآن، كل الخصائص التي عرفناها (self.brand
, self.is_running
) هي خصائص النسخة (Instance Attributes). هذا يعني أن كل كائن سيارة له نسخته الخاصة من هذه الخصائص.
لكن في بعض الأحيان، تكون هناك خاصية مشتركة بين كل الكائنات من نفس الكلاس. هذه تسمى خاصية الكلاس (Class Attribute).
class Dog:
# هذا خاصية كلاس، مشتركة بين كل الكلاب
species = "Canis familiaris"
def __init__(self, name, age):
# هذه خصائص نسخة، خاصة بكل كلب على حدة
self.name = name
self.age = age
# إنشاء نسختين (كائنين)
dog1 = Dog("Rex", 5)
dog2 = Dog("Lucy", 3)
# يمكن الوصول لخاصية الكلاس من خلال الكلاس نفسه أو من أي نسخة
print(f"فصيلة {dog1.name} هي {dog1.species}")
print(f"فصيلة {dog2.name} هي {Dog.species}")
الشرح:
خاصية species
هي نفسها لكل الكلاب، لذلك قمنا بتعريفها على مستوى الكلاس مباشرة. أما name
و age
فيختلفان من كلب لآخر، لذلك قمنا بتعريفهما داخل __init__
باستخدام self
.
6. تحسين العرض: دالة __str__
السحرية
المشكلة: ماذا يحدث إذا حاولت طباعة كائن مباشرة؟
print(my_car)
ستحصل على مخرجات غامضة مثل <__main__.Car object at 0x10d2b6a90>
. هذه هي طريقة بايثون الافتراضية لقول “هذا كائن من كلاس Car موجود في هذا العنوان في الذاكرة”. هذا غير مفيد للمستخدم.
الحل: يمكننا تحديد ما يجب طباعته عن طريق تعريف دالة سحرية أخرى هي __str__
.
الوصف:
يتم استدعاء دالة __str__
تلقائيًا كلما حاولت تحويل كائن إلى نص، وهو ما يحدث عند استخدام print()
أو str()
. يجب أن تعيد (return
) هذه الدالة نصًا (string).
class Car:
def __init__(self, brand, model, color):
self.brand = brand
self.model = model
self.color = color
# تحديد ما سيتم طباعته عند استخدام print() على الكائن
def __str__(self):
return f"سيارة من نوع {self.brand} موديل {self.model} (اللون: {self.color})"
my_pretty_car = Car("Tesla", "Model S", "أبيض")
print(my_pretty_car) # سيستدعي __str__ تلقائيًا
الناتج:
سيارة من نوع Tesla موديل Model S (اللون: أبيض)
7. تمرين تطبيقي: تصميم حساب بنكي
المطلوب:
بناء كلاس يمثل حسابًا بنكيًا (BankAccount
). يجب أن يكون الكلاس قادرًا على تتبع اسم صاحب الحساب ورصيده، والسماح بعمليات الإيداع والسحب، وعرض معلومات الحساب بشكل جيد.
الحل المقترح خطوة بخطوة:
الخطوة 1: تصميم الكلاس، المُنشئ، ودالة __str__
# تعريف كلاس الحساب البنكي
class BankAccount:
# المُنشئ لتهيئة الحساب
def __init__(self, owner_name, initial_balance=0):
# خصائص النسخة
self.owner = owner_name
self.balance = initial_balance
print(f"تم إنشاء حساب لـ {self.owner} برصيد مبدئي {self.balance} درهم.")
# دالة العرض النصي
def __str__(self):
return f"حساب بنكي باسم: {self.owner}, الرصيد الحالي: {self.balance} درهم"
الشرح:
بدأنا بتعريف الخصائص الأساسية (owner
, balance
). أضفنا دالة __str__
مباشرة لجعل طباعة معلومات الحساب سهلة وواضحة منذ البداية.
الخطوة 2: إضافة دوال الإيداع والسحب
# سنضيف الدوال إلى نفس الكلاس السابق
class BankAccount:
def __init__(self, owner_name, initial_balance=0):
self.owner = owner_name
self.balance = initial_balance
print(f"تم إنشاء حساب لـ {self.owner} برصيد مبدئي {self.balance} درهم.")
def __str__(self):
return f"حساب بنكي باسم: {self.owner}, الرصيد الحالي: {self.balance} درهم"
# دالة لإيداع المال
def deposit(self, amount):
if amount > 0:
self.balance += amount
print(f"تم إيداع {amount} درهم. الرصيد الجديد هو {self.balance} درهم.")
else:
print("مبلغ الإيداع يجب أن يكون موجبًا.")
# دالة لسحب المال
def withdraw(self, amount):
if amount <= 0:
print("مبلغ السحب يجب أن يكون موجبًا.")
elif amount > self.balance:
print("فشل السحب: الرصيد غير كافٍ.")
else:
self.balance -= amount
print(f"تم سحب {amount} درهم. الرصيد الجديد هو {self.balance} درهم.")
الشرح:
أضفنا منطق التحقق داخل دالتي deposit
و withdraw
للتأكد من أن العمليات تتم بشكل صحيح (المبالغ موجبة، الرصيد كافٍ). لاحظ كيف أن كل دالة تستخدم self.balance
للوصول إلى رصيد هذا الحساب تحديدًا وتعديله.
الخطوة 3: استخدام الكلاس
# إنشاء كائن حساب بنكي جديد
account1 = BankAccount("أحمد", 500)
print("\n--- عرض معلومات الحساب ---")
# طباعة الكائن مباشرة ستستخدم دالة __str__
print(account1)
print("\n--- إجراء المعاملات ---")
account1.deposit(200) # إيداع
account1.withdraw(100) # سحب
account1.withdraw(700) # محاولة سحب مبلغ أكبر من الرصيد
account1.deposit(-50) # محاولة إيداع مبلغ سالب
print("\n--- الحالة النهائية للحساب ---")
print(account1)
الشرح:
نرى هنا قوة OOP في العمل. أنشأنا كائنًا account1
، ثم بدأنا بالتفاعل معه باستخدام الدوال التي صممناها. الكود منظم وسهل القراءة، حيث أن كل عملية (إيداع، سحب) هي استدعاء لدالة واضحة الاسم على الكائن الذي يخص “أحمد”.
تمارين تطبيقية مع الحلول
التمرين 1: كلاس الكتاب الأساسي
المطلوب:
أنشئ كلاسًا باسم Book
. يجب أن يحتوي المُنشئ __init__
على معاملين هما title
و author
. قم بتخزين هاتين القيمتين كخصائص للنسخة (instance attributes). بعد ذلك، أنشئ كائنًا (نسخة) من هذا الكلاس وقم بطباعة عنوانه ومؤلفه.
الحل:
# --- الحل للتمرين 1 ---
# 1. تعريف الكلاس
class Book:
# 2. تعريف المُنشئ لتهيئة الخصائص
def __init__(self, title, author):
self.title = title
self.author = author
# 3. إنشاء كائن (نسخة) من الكلاس
my_book = Book("مقدمة ابن خلدون", "ابن خلدون")
# 4. الوصول إلى الخصائص وطباعتها
print(f"العنوان: {my_book.title}")
print(f"المؤلف: {my_book.author}")
التمرين 2: إضافة دالة (Method)
المطلوب:
بناءً على الكلاس Book
من التمرين السابق، أضف دالة (method) باسم get_description
لا تأخذ أي معاملات (باستثناء self
) وتعيد (return
) نصًا يجمع العنوان والمؤلف بالصيغة التالية: “[العنوان]
من تأليف [المؤلف]
”.
الحل:
# --- الحل للتمرين 2 ---
class Book:
def __init__(self, title, author):
self.title = title
self.author = author
# 1. إضافة الدالة الجديدة
def get_description(self):
return f"'{self.title}' من تأليف {self.author}"
# إنشاء كائن
my_book = Book("مقدمة ابن خلدون", "ابن خلدون")
# استدعاء الدالة وتخزين النتيجة في متغير
description = my_book.get_description()
# طباعة الوصف
print(description)
التمرين 3: استخدام دالة __str__
المطلوب:
عدّل الكلاس Book
من التمرين السابق. بدلاً من دالة get_description
، قم بتنفيذ الدالة السحرية __str__
لتقوم بنفس المهمة. بعد ذلك، قم بإنشاء كائن من الكلاس واستخدم print()
مباشرة على الكائن لترى كيف يتم عرض الوصف المنسق.
الحل:
# --- الحل للتمرين 3 ---
class Book:
def __init__(self, title, author):
self.title = title
self.author = author
# 1. تنفيذ الدالة السحرية __str__
def __str__(self):
# يجب أن تعيد هذه الدالة نصًا
return f"'{self.title}' من تأليف {self.author}"
# إنشاء كائن
my_book = Book("مقدمة ابن خلدون", "ابن خلدون")
# طباعة الكائن مباشرة ستستدعي دالة __str__ تلقائيًا
print(my_book)
التمرين 4: كلاس الدائرة
المطلوب:
أنشئ كلاسًا باسم Circle
. يجب أن يأخذ المُنشئ معاملًا واحدًا هو radius
(نصف القطر). قم بإنشاء دالتين:
calculate_area()
: تحسب مساحة الدائرة وتعيدها. (المعادلة: $Area = \pi \times r^2$)calculate_circumference()
: تحسب محيط الدائرة وتعيده. (المعادلة: $Circumference = 2 \times \pi \times r$) استخدم القيمة3.14159
لـ $\pi$.
الحل:
# --- الحل للتمرين 4 ---
class Circle:
# استخدام خاصية كلاس لـ PI لأنها ثابتة لكل الدوائر
pi = 3.14159
def __init__(self, radius):
self.radius = radius
# دالة لحساب المساحة
def calculate_area(self):
return self.pi * (self.radius ** 2)
# دالة لحساب المحيط
def calculate_circumference(self):
return 2 * self.pi * self.radius
# إنشاء دائرة نصف قطرها 10
c1 = Circle(10)
# حساب وطباعة المساحة والمحيط
print(f"مساحة الدائرة: {c1.calculate_area():.2f}")
print(f"محيط الدائرة: {c1.calculate_circumference():.2f}")
التمرين 5: تتبع عدد الكائنات (خاصية الكلاس)
المطلوب:
أنشئ كلاسًا باسم Employee
.
- أضف خاصية كلاس باسم
employee_count
وقيمتها الأولية0
. - في المُنشئ
__init__
، الذي يجب أن يأخذname
الموظف، قم بزيادة قيمةemployee_count
بمقدار1
في كل مرة يتم فيها إنشاء موظف جديد. - أنشئ ثلاثة كائنات من الموظفين، ثم اطبع العدد الإجمالي للموظفين باستخدام خاصية الكلاس.
الحل:
# --- الحل للتمرين 5 ---
class Employee:
# هذه خاصية كلاس، مشتركة بين كل الموظفين
employee_count = 0
def __init__(self, name):
# هذه خاصية نسخة، خاصة بكل موظف
self.name = name
print(f"تم إنشاء حساب للموظف: {self.name}")
# زيادة عداد الكلاس في كل مرة يتم فيها إنشاء كائن جديد
Employee.employee_count += 1
# إنشاء ثلاثة موظفين
emp1 = Employee("أحمد")
emp2 = Employee("سارة")
emp3 = Employee("علي")
# طباعة العدد الإجمالي للموظفين
print(f"\nالعدد الإجمالي للموظفين هو: {Employee.employee_count}")
التمرين 6: تعديل حالة الكائن
المطلوب:
أنشئ كلاسًا باسم Elevator
(مصعد). يجب أن يحتوي المُنشئ على خاصية current_floor
تبدأ من 0
. أنشئ دالتين:
go_up()
: تزيدcurrent_floor
بمقدار1
.go_down()
: تنقصcurrent_floor
بمقدار1
، ولكن يجب ألا ينزل المصعد تحت الطابق0
.
الحل:
# --- الحل للتمرين 6 ---
class Elevator:
def __init__(self):
self.current_floor = 0
print(f"المصعد الآن في الطابق: {self.current_floor}")
def go_up(self):
self.current_floor += 1
print(f"صعود... الطابق الحالي: {self.current_floor}")
def go_down(self):
if self.current_floor > 0:
self.current_floor -= 1
print(f"نزول... الطابق الحالي: {self.current_floor}")
else:
print("لا يمكن النزول، المصعد في الطابق الأرضي.")
# إنشاء مصعد جديد
elevator1 = Elevator()
# تجربة المصعد
elevator1.go_up()
elevator1.go_up()
elevator1.go_down()
elevator1.go_down()
elevator1.go_down() # سيمنعه من النزول
التمرين 7: كلاس بقائمة كخاصية
المطلوب:
أنشئ كلاس Playlist
يمثل قائمة تشغيل أغاني.
- في المُنشئ، قم بتهيئة خاصية
songs
كقائمة فارغة[]
. - أنشئ دالة
add_song(song_title)
تضيف أغنية جديدة إلى قائمةsongs
. - أنشئ دالة
show_playlist()
تطبع كل الأغاني الموجودة في القائمة.
الحل:
# --- الحل للتمرين 7 ---
class Playlist:
def __init__(self, name):
self.name = name
self.songs = [] # خاصية من نوع قائمة
print(f"تم إنشاء قائمة التشغيل: {self.name}")
def add_song(self, song_title):
self.songs.append(song_title)
print(f"تمت إضافة '{song_title}' إلى القائمة.")
def show_playlist(self):
print(f"\n--- أغاني قائمة '{self.name}' ---")
if not self.songs:
print("القائمة فارغة.")
else:
for song in self.songs:
print(f"- {song}")
# إنشاء قائمة تشغيل
my_playlist = Playlist("أغاني الصباح")
# إضافة أغاني
my_playlist.add_song("أغنية فيروز")
my_playlist.add_song("أغنية أم كلثوم")
# عرض القائمة
my_playlist.show_playlist()
التمرين 8: تفاعل بين الكائنات
المطلوب:
أنشئ كلاس Warrior
(محارب) له الخصائص name
و health
(الصحة، تبدأ من 100). أضف دالة attack(other_warrior)
تأخذ كائن محارب آخر كوسيط. عند استدعائها، يجب أن تقلل صحة المحارب الآخر بمقدار 10 وتطبع رسالة تصف الهجوم.
الحل:
# --- الحل للتمرين 8 ---
class Warrior:
def __init__(self, name):
self.name = name
self.health = 100
def __str__(self):
return f"المحارب {self.name} (الصحة: {self.health})"
def attack(self, other_warrior):
print(f"{self.name} يهاجم {other_warrior.name}!")
# تقليل صحة المحارب الآخر
other_warrior.health -= 10
print(f"صحة {other_warrior.name} أصبحت الآن {other_warrior.health}.")
# إنشاء محاربين
warrior1 = Warrior("آرثر")
warrior2 = Warrior("لان سلوت")
# عرض الحالة الأولية
print(warrior1)
print(warrior2)
# بدء الهجوم
print("\n--- المعركة تبدأ ---")
warrior1.attack(warrior2)
warrior2.attack(warrior1)
warrior1.attack(warrior2)
# عرض الحالة النهائية
print("\n--- بعد المعركة ---")
print(warrior1)
print(warrior2)
التمرين 9: كلاس بـ قاموس كخاصية
المطلوب:
أنشئ كلاس Product
يمثل منتجًا في متجر.
- المُنشئ يأخذ
name
وprice
. - أضف خاصية
details
تكون عبارة عن قاموس فارغ{}
. - أنشئ دالة
add_detail(key, value)
تضيف معلومة جديدة إلى قاموسdetails
. - نفذ دالة
__str__
لعرض كل معلومات المنتج بشكل جيد.
الحل:
# --- الحل للتمرين 9 ---
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
self.details = {} # خاصية من نوع قاموس
def add_detail(self, key, value):
self.details[key] = value
print(f"تمت إضافة التفصيل: {key}")
def __str__(self):
# بناء نص التفاصيل
details_text = "\n".join([f"- {key}: {value}" for key, value in self.details.items()])
return (f"--- المنتج: {self.name} ---\n"
f"السعر: {self.price} درهم\n"
f"التفاصيل:\n{details_text}")
# إنشاء منتج
my_product = Product("لابتوب", 4500)
# إضافة تفاصيل
my_product.add_detail("المعالج", "Core i5")
my_product.add_detail("الذاكرة", "8GB RAM")
my_product.add_detail("اللون", "فضي")
# طباعة المنتج
print("\n" + str(my_product))
التمرين 10: كلاس السيارة مع عداد السرعة
المطلوب:
أنشئ كلاس Car
له خاصية speed
تبدأ من 0
. أنشئ دالتين:
accelerate()
: تزيد السرعة بمقدار 5.brake()
: تنقص السرعة بمقدار 5. يجب ألا تقل السرعة عن0
. بعد كل عملية، اطبع السرعة الحالية.
الحل:
# --- الحل للتمرين 10 ---
class Car:
def __init__(self, brand):
self.brand = brand
self.speed = 0
print(f"تم إنشاء سيارة من نوع {self.brand}. السرعة الحالية: {self.speed} كم/س")
def accelerate(self):
self.speed += 5
print(f"تسارع... السرعة الحالية: {self.speed} كم/س")
def brake(self):
if self.speed >= 5:
self.speed -= 5
else:
self.speed = 0 # لضمان عدم نزولها تحت الصفر
print(f"فرملة... السرعة الحالية: {self.speed} كم/س")
# إنشاء سيارة
my_car = Car("Honda")
# تجربة السيارة
my_car.accelerate()
my_car.accelerate()
my_car.brake()
my_car.brake()
my_car.brake() # لن تنزل تحت الصفر
8. خلاصة الفصل
- البرمجة كائنية التوجه (OOP) هي نمط لتنظيم الكود عن طريق تجميع البيانات (الخصائص) والسلوكيات (الدوال) معًا في كائنات.
- الكلاس (Class) هو المخطط أو القالب الذي نستخدمه لإنشاء الكائنات.
- الكائن (Object/Instance) هو نسخة حقيقية يتم إنشاؤها من الكلاس، ولكل كائن حالته الخاصة.
- دالة
__init__
هي المُنشئ الذي يهيئ خصائص الكائن عند إنشائه. - خصائص النسخة (Instance Attributes) هي بيانات خاصة بكل كائن (
self.name
). - خصائص الكلاس (Class Attributes) هي بيانات مشتركة بين كل كائنات الكلاس.
- الدوال (Methods) هي أفعال الكائن، وتأخذ
self
دائمًا كأول معامل. - دالة
__str__
تسمح لنا بتحديد تمثيل نصي سهل القراءة للكائن.