Kodax

مقدمة في OOP — البرمجة الكائنية

مقدمة في البرمجة الكائنية (OOP)

حتى الآن نظمت برامجك بالدوال، والبيانات منفصلة عنها في قوائم وقواميس. هذا يعمل جيداً للبرامج الصغيرة. لكن عندما يكبر البرنامج تظهر مشكلة: دالة withdraw(account, amount) يمكن أن تُستدعى على أي قاموس، وأي جزء من الكود يمكنه تغيير account["balance"] مباشرة إلى قيمة خاطئة.

البرمجة الكائنية تجمع البيانات والدوال التي تعمل عليها في وحدة واحدة تسمى كائناً.

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

- الصنف (class): المخطط أو القالب. مثل تصميم سيارة.

- الكائن (object / instance): نسخة حقيقية من الصنف. مثل سيارة محددة لها لون ورقم.

class Dog:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def bark(self):
        return f"{self.name} ينبح!"

rex = Dog("ريكس", 3)     # إنشاء كائن
print(rex.name)          # خاصية
print(rex.bark())        # دالة (method)

__init__ و self

- __init__ تُستدعى تلقائياً عند إنشاء الكائن، ومهمتها تهيئة خصائصه.

- self تشير إلى الكائن نفسه الذي تعمل عليه الدالة. عندما تكتب rex.bark() فإن Python تنفذ فعلياً Dog.bark(rex)، فيصبح self هو rex.

- كل دالة داخل الصنف تأخذ self كمعامل أول.

خصائص الكائن وخصائص الصنف

class Car:
    wheels = 4                 # خاصية صنف: مشتركة بين كل الكائنات
    def __init__(self, brand):
        self.brand = brand     # خاصية كائن: لكل سيارة قيمتها

__str__ للطباعة

بدون __str__، طباعة الكائن تعرض شيئاً مثل <__main__.Car object at 0x...>. عرّفها لتمثيل مقروء:

def __str__(self):
    return f"سيارة {self.brand}"

متى تستخدم الأصناف؟

عندما يكون لديك "شيء" له حالة (بيانات تتغير) وسلوك (عمليات عليها): حساب بنكي، لاعب في لعبة، طلب شراء. للعمليات البسيطة بلا حالة، الدوال العادية أبسط وأفضل.

خطأ شائع

نسيان self في تعريف الدالة: def bark(): ثم rex.bark() ← TypeError: takes 0 positional arguments but 1 was given، لأن Python تمرر الكائن تلقائياً.

تمرين

أنشئ صنف Rectangle بخاصيتي العرض والارتفاع، ودوال area() و perimeter() و __str__، وأنشئ منه كائنين واطبعهما.

# تعريف صنف
class Person:
    # Constructor - يُستدعى عند إنشاء كائن
    def __init__(self, name, age):
        self.name = name  # خاصية
        self.age = age
    
    # Method - دالة
    def greet(self):
        return f"مرحباً، أنا {self.name}"
    
    def have_birthday(self):
        self.age += 1
        return f"عيد ميلاد سعيد! عمري الآن {self.age}"

# إنشاء كائنات
person1 = Person("أحمد", 25)
person2 = Person("محمد", 30)

print(person1.name)     # أحمد
print(person1.greet())  # مرحباً، أنا أحمد
print(person1.have_birthday())

# صنف مع قيم افتراضية
class Car:
    # Class attribute (مشترك بين كل الكائنات)
    wheels = 4
    
    def __init__(self, brand, model, year=2024):
        # Instance attributes
        self.brand = brand
        self.model = model
        self.year = year
        self.speed = 0
    
    def accelerate(self, amount):
        self.speed += amount
        return f"السرعة الآن: {self.speed} كم/س"
    
    def brake(self):
        self.speed = max(0, self.speed - 10)
        return f"السرعة الآن: {self.speed} كم/س"
    
    def __str__(self):
        return f"{self.year} {self.brand} {self.model}"

car = Car("تويوتا", "كامري")
print(car)  # 2024 تويوتا كامري
print(car.accelerate(50))
print(Car.wheels)  # 4
اختبر فهمك