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

في الدروس القليلة الماضية، نظّمنا الكود باستخدام الدوال — نهج "إجرائي" يركز على "ماذا تفعل." البرمجة كائنية التوجه (OOP) تركز على "من يفعل" — تضمين البيانات والطرق التي تعمل على تلك البيانات في كائن. كل شيء في بايثون هو كائن؛ فهم OOP هو خطوة رئيسية للأمام.


1. ما هي الفئات والكائنات

الفئة هي مخطط؛ الكائن هو نسخة ملموسة تم إنشاؤها من ذلك المخطط.

PYTHON
# عرّف فئة "كلب" — المخطط
class Dog:
    pass

# أنشئ كائنات "كلب" محددة من المخطط
my_dog = Dog()
print(type(my_dog))         # <class '__main__.Dog'>
print(my_dog)               # <__main__.Dog object at 0x...>

مثل "الكلب" كسلالة هو مفهوم (فئة)، الكلب المحدد المسمى Wangcai الذي تملكه هو نسخة (كائن). فئة واحدة يمكنها إنشاء عدد لا يحصى من الكائنات.

💡 تشبيه من الواقع: الفئة هي "المخطط"، الكائن هو "الشيء المادي المبني من المخطط." مخطط واحد يمكنه إنتاج أشياء مادية كثيرة، لكل منها حالته الخاصة (مثل الكلاب المختلفة لها أسماء وأعمار مختلفة).


2. __init__: طريقة المُنشئ

عند إنشاء كائن، يتم استدعاء طريقة __init__ تلقائياً لتهيئة سمات الكائن:

PYTHON
class Dog:
    """فئة الكلب"""
    def __init__(self, name, age):
        self.name = name    # سمة المثال
        self.age = age

# مرر المعاملات عند إنشاء الكائنات
dog1 = Dog("Wangcai", 3)
dog2 = Dog("Xiaobai", 1)

print(dog1.name)            # Wangcai
print(dog2.name)            # Xiaobai
print(dog1.age)             # 3

ملاحظة: __init__ ليس المُنشئ — الكائن يُنشأ قبل استدعائه. المُنشئ الفعلي هو __new__، لكنك لا تحتاج أبداً للمساس به تقريباً. المعامل الأول لـ __init__ هو دائماً self، الذي يمثل نسخة الكائن الحالية.

مثال: تعريف فئة طالب (الصعوبة ⭐)

PYTHON
class Student:
    """فئة الطالب"""
    def __init__(self, name, student_id, score):
        self.name = name
        self.student_id = student_id
        self.score = score

    def introduce(self):
        """تقديم الذات"""
        return f"My name is {self.name}, ID: {self.student_id}, score: {self.score}."
    
    def is_pass(self):
        """تحقق من النجاح"""
        return self.score >= 60

# أنشئ كائنات الطلاب
s1 = Student("Zhang San", "2024001", 85)
s2 = Student("Li Si", "2024002", 45)

print(s1.introduce())       # My name is Zhang San, ID: 2024001, score: 85.
print(s2.introduce())       # My name is Li Si, ID: 2024002, score: 45.
print(f"Is Zhang San passing? {s1.is_pass()}")   # True
print(f"Is Li Si passing? {s2.is_pass()}")   # False
▶ جرّب الكود

3. الطرق: سلوكيات الكائن

الدوال المُعرّفة داخل الفئة تُسمى طرقاً. معاملها الأول هو دائماً self — الذي يمثل الكائن نفسه الذي يستدعي الطريقة.

PYTHON
class Calculator:
    """آلة حاسبة بسيطة"""
    def __init__(self):
        self.result = 0
    
    def add(self, value):
        self.result += value
        return self
    
    def subtract(self, value):
        self.result -= value
        return self
    
    def show(self):
        return self.result

calc = Calculator()
calc.add(10)
calc.subtract(3)
print(calc.show())                  # 7

# تسلسل الطرق — كل طريقة تُرجع self
result = Calculator().add(10).subtract(3).add(5).show()
print(result)                       # 12
💡 خدعة تسلسل الطرق: الطرق التي تُرجع self يمكن تسلسلها. العديد من مكتبات بايثون (مثل pandas) تستخدم هذا النمط بشكل مكثف.


4. سمات المثال مقابل سمات الفئة

يمكن تعريف السمات على المثال (فريدة لكل كائن) أو على الفئة (مشتركة بين جميع الكائنات):

PYTHON
class Student:
    # سمة الفئة — مشتركة بين جميع الطلاب
    school = "First High School"
    total_count = 0
    
    def __init__(self, name):
        # سمة المثال — فريدة لكل طالب
        self.name = name
        Student.total_count += 1

s1 = Student("Zhang San")
s2 = Student("Li Si")

# سمات الفئة تُتاح عبر اسم الفئة
print(Student.school)       # First High School
print(Student.total_count)  # 2

# يمكن الوصول إليها أيضاً عبر المثيلات (إذا لم توجد سمة مثال بنفس الاسم)
print(s1.school)            # First High School
print(s2.school)            # First High School

# تعديل سمة الفئة يؤثر على جميع المثيلات
Student.school = "Second High School"
print(s1.school)            # Second High School

مثال: حساب بنكي (الصعوبة ⭐⭐)

PYTHON
class BankAccount:
    """حساب بنكي"""
    bank_name = "Python Bank"          # سمة فئة
    interest_rate = 0.003              # معدل فائدة سنوي 0.3%
    
    def __init__(self, owner, balance=0):
        self.owner = owner            # سمة مثال
        self.balance = balance        # سمة مثال
    
    def deposit(self, amount):
        self.balance += amount
        return f"Deposited {amount}, balance: {self.balance}"
    
    def withdraw(self, amount):
        if amount > self.balance:
            return "Insufficient balance!"
        self.balance -= amount
        return f"Withdrew {amount}, balance: {self.balance}"
    
    def yearly_interest(self):
        """احسب الفائدة السنوية"""
        interest = self.balance * BankAccount.interest_rate
        return f"Yearly interest: {interest:.2f}"

acc1 = BankAccount("Zhang San", 10000)
acc2 = BankAccount("Li Si", 5000)

print(acc1.deposit(5000))           # Deposited 5000, balance: 15000
print(acc2.withdraw(2000))          # Withdrew 2000, balance: 3000
print(acc1.yearly_interest())       # Yearly interest: 4.50

# جميع الحسابات تشترك في نفس معدل الفائدة
print(acc1.interest_rate)           # 0.003
print(acc2.interest_rate)           # 0.003
▶ جرّب الكود

حالات الاستخدام الشائعة


❓ أسئلة شائعة

س ما الفرق بين الطريقة والدالة؟
ج الطريقة هي دالة مُعرّفة داخل فئة، مع self كأول معامل. الدوال يمكن أن توجد بشكل مستقل؛ الطرق يجب أن تُستدعَى عبر كائن أو فئة. أساساً، الطرق هي دوال حيث تمرر بايثون المتصل تلقائياً كأول وسيطة. س:هل يمكن إعادة تسمية self إلى شيء آخر؟ ج:تقنياً نعم، لكن لا تغيره أبداً. self هي قاعدة صارمة في مجتمع بايثون. تغيير الاسم سيعمل، لكن أي شخص يقرأ كودك (بما فيهم أنت في المستقبل) سيجده غريباً. استخدم دائماً self. س:متى يجب استخدام فئة مقابل دالة؟ ج:إذا كنت بحاجة للحفاظ على حالة (بيانات)، استخدم فئة — مثل حساب بنكي يتتبع الرصيد. إذا كنت تقوم بحساب لمرة واحدة (إدخال ← معالجة ← إخراج)، استخدم دالة — مثل تحويل درجة الحرارة. قاعدة بسيطة: إذا كنت تحتاج فقط 1-2 دالة، الدوال كافية؛ إذا كانت دوال متعددة ذات صلة تشارك نفس البيانات، استخدم فئة.

📖 ملخص

  • الفئة هي مخطط؛ الكائن هو نسخة ملموسة تم إنشاؤها منه
  • __init__ هي طريقة التهيئة، تُستدعى تلقائياً عند إنشاء كائن
  • المعامل الأول للطرق هو self، الذي يمثل الكائن الحالي
  • سمات المثال فريدة لكل كائن؛ سمات الفئة مشتركة بين جميع الكائنات
  • الفئات تضم البيانات والطرق التي تعمل على تلك البيانات معاً

📝 تمارين

  1. مبتدئ (الصعوبة ⭐): عرّف فئة Car بسمات brand و color و speed. تضمين طريقة accelerate(value) لزيادة السرعة وطريقة show_speed() لعرض السرعة الحالية.

  2. متوسط (الصعوبة ⭐⭐): عرّف فئة Student. استخدم سمة فئة لتتبع العدد الإجمالي للطلاب، وسمات مثال لتسجيل اسم ودرجة كل طالب. نفّذ طريقة get_grade() تُرجع تقديراً حرفياً (A, B, C, D).

  3. متقدم (الصعوبة ⭐⭐⭐): عرّف فئة Library وفئة Book. Book لها عنوان ومؤلف وحالة استعارة. Library لها أربع طرق: add_book(book)، borrow(title)، return_book(title)، و show_books().

100%