الأساليب (Methods) في Python: السلوكيات والوظائف

في الدروس السابقة، تعلمنا عن الخصائص (Attributes) - البيانات التي يحملها الكائن. الآن حان الوقت لتعلم الأساليب (Methods) - الأفعال والسلوكيات التي يمكن للكائن القيام بها. الأساليب هي ببساطة دوال تعيش داخل الصنف وتعمل على بيانات الكائن. إنها ما يجعل الكائنات "حية" وقادرة على التفاعل والقيام بالمهام.

1. ما هي الأساليب (Methods)؟

التعريف الأساسي

الأساليب (Methods) هي دوال تُعرّف داخل الصنف. الفرق الرئيسي بين الدالة العادية والأسلوب:

  • الدالة العادية: مستقلة، لا تنتمي لأي شيء، تستقبل بيانات كمعاملات
  • الأسلوب (Method): ينتمي لصنف، يعمل على بيانات الكائن، يبدأ دائماً بـ self

الأساليب تمثل "السلوكيات" أو "الأفعال" التي يمكن للكائن القيام بها:

  • كلب يمكنه: النباح، الأكل، النوم، الجري
  • حساب بنكي يمكنه: الإيداع، السحب، عرض الرصيد، تحويل الأموال
  • سيارة يمكنها: التسارع، الفرملة، تشغيل المحرك، إيقاف المحرك
مثال بسيط جداً
simple_method.py
class Dog:
    def __init__(self, name):
        self.name = name
    
    def bark(self):
        print(f"{self.name} ينبح: واف واف!")

# إنشاء كلب
my_dog = Dog("ماكس")

# استدعاء الأسلوب
my_dog.bark()
النتيجة
ماكس ينبح: واف واف!

شرح الكود سطراً بسطر:

  • السطر 1: نعرّف صنف Dog
  • السطر 2-3: دالة __init__ لتهيئة اسم الكلب
  • السطر 5: نعرّف أسلوباً اسمه bark. لاحظ أنه يبدأ بـ self
  • السطر 6: الأسلوب يطبع رسالة تحتوي على اسم الكلب (self.name)
  • السطر 9: ننشئ كائن كلب اسمه "ماكس"
  • السطر 12: نستدعي الأسلوب bark. لاحظ أننا لم نمرر self - بايثون تفعل ذلك تلقائياً!

2. أساليب تستقبل معاملات

تمرير بيانات إضافية للأساليب

مثل الدوال العادية، يمكن للأساليب استقبال معاملات إضافية (بعد self):

methods_with_params.py
class BankAccount:
    def __init__(self, owner, balance):
        self.owner = owner
        self.balance = balance
    
    def deposit(self, amount):
        """إيداع مبلغ في الحساب"""
        self.balance += amount
        print(f"تم إيداع {amount} ريال")
        print(f"الرصيد الجديد: {self.balance} ريال")
    
    def withdraw(self, amount):
        """سحب مبلغ من الحساب"""
        if amount > self.balance:
            print(f"رصيد غير كافي! الرصيد الحالي: {self.balance}")
        else:
            self.balance -= amount
            print(f"تم سحب {amount} ريال")
            print(f"الرصيد المتبقي: {self.balance} ريال")

# إنشاء حساب
account = BankAccount("أحمد", 1000)

# استخدام الأساليب
account.deposit(500)
print()
account.withdraw(300)
print()
account.withdraw(2000)  # محاولة سحب أكثر من الرصيد
النتيجة
تم إيداع 500 ريال الرصيد الجديد: 1500 ريال تم سحب 300 ريال الرصيد المتبقي: 1200 ريال رصيد غير كافي! الرصيد الحالي: 1200

شرح الكود سطراً بسطر:

  • السطر 1: تعريف صنف BankAccount (حساب بنكي)
  • السطر 2-4: دالة __init__ تستقبل اسم المالك والرصيد الأولي
  • السطر 6: تعريف أسلوب deposit (إيداع) يستقبل self و amount (المبلغ)
  • السطر 8: نضيف المبلغ إلى الرصيد الحالي (self.balance)
  • السطر 9-10: نطبع رسائل تأكيد
  • السطر 12: تعريف أسلوب withdraw (سحب)
  • السطر 14: نتحقق: هل المبلغ المطلوب أكبر من الرصيد؟
  • السطر 15: إذا كان كذلك، نطبع رسالة خطأ
  • السطر 17: إذا كان الرصيد كافياً، نطرح المبلغ
  • السطر 22: ننشئ حساباً برصيد أولي 1000 ريال
  • السطر 25: نستدعي deposit(500) - نمرر المبلغ فقط، بايثون تمرر self تلقائياً
  • السطر 27: نسحب 300 ريال (سينجح لأن الرصيد كافٍ)
  • السطر 29: نحاول سحب 2000 ريال (سيفشل لأن الرصيد غير كافٍ)

3. أساليب تُرجع قيماً

استخدام return في الأساليب

الأساليب يمكنها إرجاع قيم تماماً مثل الدوال العادية:

methods_with_return.py
class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    def get_area(self):
        """حساب المساحة"""
        area = self.width * self.height
        return area
    
    def get_perimeter(self):
        """حساب المحيط"""
        perimeter = 2 * (self.width + self.height)
        return perimeter
    
    def is_square(self):
        """التحقق: هل هو مربع؟"""
        return self.width == self.height

# إنشاء مستطيل
rect1 = Rectangle(5, 10)
rect2 = Rectangle(7, 7)

# استخدام الأساليب التي تُرجع قيماً
area1 = rect1.get_area()
print(f"مساحة المستطيل 1: {area1}")

perimeter1 = rect1.get_perimeter()
print(f"محيط المستطيل 1: {perimeter1}")

# استخدام القيمة المُرجعة مباشرة
print(f"هل المستطيل 1 مربع؟ {rect1.is_square()}")
print(f"هل المستطيل 2 مربع؟ {rect2.is_square()}")
النتيجة
مساحة المستطيل 1: 50 محيط المستطيل 1: 30 هل المستطيل 1 مربع؟ False هل المستطيل 2 مربع؟ True

شرح الكود سطراً بسطر:

  • السطر 1: تعريف صنف Rectangle (مستطيل)
  • السطر 2-4: تهيئة العرض والارتفاع
  • السطر 6-9: أسلوب get_area يحسب المساحة (العرض × الارتفاع) ويُرجعها
  • السطر 11-14: أسلوب get_perimeter يحسب المحيط ويُرجعه
  • السطر 16-18: أسلوب is_square يتحقق: هل العرض يساوي الارتفاع؟ يُرجع True أو False
  • السطر 21: ننشئ مستطيلاً عرضه 5 وارتفاعه 10
  • السطر 22: ننشئ مستطيلاً عرضه 7 وارتفاعه 7 (مربع!)
  • السطر 25: نستدعي get_area() ونحفظ النتيجة في متغير
  • السطر 32: نستخدم القيمة المُرجعة مباشرة في print بدون حفظها

4. أساليب تستدعي أساليب أخرى

التعاون بين الأساليب

الأساليب يمكنها استدعاء أساليب أخرى داخل نفس الصنف باستخدام self:

methods_calling_methods.py
class Student:
    def __init__(self, name):
        self.name = name
        self.grades = []
    
    def add_grade(self, grade):
        """إضافة درجة"""
        self.grades.append(grade)
        print(f"تم إضافة درجة {grade} للطالب {self.name}")
    
    def get_average(self):
        """حساب المعدل"""
        if not self.grades:
            return 0
        return sum(self.grades) / len(self.grades)
    
    def get_status(self):
        """تحديد حالة النجاح/الرسوب"""
        # استدعاء أسلوب آخر من نفس الصنف
        average = self.get_average()
        
        if average >= 50:
            return "ناجح"
        else:
            return "راسب"
    
    def display_report(self):
        """عرض تقرير كامل"""
        # استدعاء عدة أساليب
        average = self.get_average()
        status = self.get_status()
        
        print(f"\n{'='*40}")
        print(f"تقرير الطالب: {self.name}")
        print(f"{'='*40}")
        print(f"الدرجات: {self.grades}")
        print(f"المعدل: {average:.2f}")
        print(f"الحالة: {status}")
        print(f"{'='*40}")

# استخدام الصنف
student = Student("أحمد")

# إضافة درجات
student.add_grade(85)
student.add_grade(90)
student.add_grade(78)

# عرض التقرير (يستدعي أساليب أخرى داخلياً)
student.display_report()
النتيجة
تم إضافة درجة 85 للطالب أحمد تم إضافة درجة 90 للطالب أحمد تم إضافة درجة 78 للطالب أحمد ======================================== تقرير الطالب: أحمد ======================================== الدرجات: [85, 90, 78] المعدل: 84.33 الحالة: ناجح ========================================

شرح الكود سطراً بسطر:

  • السطر 1-4: تعريف الصنف وتهيئة اسم الطالب وقائمة فارغة للدرجات
  • السطر 6-9: أسلوب add_grade يضيف درجة للقائمة
  • السطر 11-15: أسلوب get_average يحسب المعدل (مجموع الدرجات ÷ عددها)
  • السطر 17-25: أسلوب get_status يحدد النجاح/الرسوب
  • السطر 20: مهم! نستدعي self.get_average() - أسلوب يستدعي أسلوباً آخر
  • السطر 27-39: أسلوب display_report يعرض تقريراً كاملاً
  • السطر 30-31: يستدعي أسلوبين آخرين (get_average و get_status)
  • السطر 42: ننشئ طالباً
  • السطر 45-47: نضيف 3 درجات
  • السطر 50: نستدعي display_report الذي يستدعي الأساليب الأخرى تلقائياً

5. مثال عملي شامل: نظام إدارة مهام

تطبيق متكامل

لنبني نظاماً كاملاً لإدارة المهام يجمع كل ما تعلمناه:

task_manager.py
class TaskManager:
    """نظام إدارة المهام"""
    
    def __init__(self, owner):
        self.owner = owner
        self.tasks = []  # قائمة المهام
        self.completed_tasks = []  # المهام المكتملة
    
    def add_task(self, task_name, priority="متوسطة"):
        """إضافة مهمة جديدة"""
        task = {
            'name': task_name,
            'priority': priority,
            'completed': False
        }
        self.tasks.append(task)
        print(f"تمت إضافة المهمة: {task_name} (أولوية: {priority})")
    
    def complete_task(self, task_name):
        """تحديد مهمة كمكتملة"""
        for task in self.tasks:
            if task['name'] == task_name and not task['completed']:
                task['completed'] = True
                self.completed_tasks.append(task)
                print(f"تم إكمال المهمة: {task_name}")
                return True
        print(f"لم يتم العثور على المهمة: {task_name}")
        return False
    
    def get_pending_count(self):
        """عدد المهام المعلقة"""
        count = 0
        for task in self.tasks:
            if not task['completed']:
                count += 1
        return count
    
    def get_completed_count(self):
        """عدد المهام المكتملة"""
        return len(self.completed_tasks)
    
    def get_completion_rate(self):
        """نسبة الإنجاز"""
        if not self.tasks:
            return 0
        completed = self.get_completed_count()
        total = len(self.tasks)
        return (completed / total) * 100
    
    def display_summary(self):
        """عرض ملخص المهام"""
        print(f"\n{'='*50}")
        print(f"ملخص مهام: {self.owner}")
        print(f"{'='*50}")
        print(f"إجمالي المهام: {len(self.tasks)}")
        print(f"المهام المكتملة: {self.get_completed_count()}")
        print(f"المهام المعلقة: {self.get_pending_count()}")
        print(f"نسبة الإنجاز: {self.get_completion_rate():.1f}%")
        print(f"{'='*50}")
    
    def display_all_tasks(self):
        """عرض جميع المهام"""
        print(f"\n--- قائمة مهام {self.owner} ---")
        if not self.tasks:
            print("لا توجد مهام")
            return
        
        for i, task in enumerate(self.tasks, 1):
            status = "✓ مكتملة" if task['completed'] else "○ معلقة"
            print(f"{i}. {task['name']} - {task['priority']} - {status}")

# استخدام النظام
print("=== نظام إدارة المهام ===\n")

# إنشاء مدير مهام
manager = TaskManager("أحمد")

# إضافة مهام
manager.add_task("كتابة التقرير الشهري", "عالية")
manager.add_task("مراجعة البريد الإلكتروني", "متوسطة")
manager.add_task("الاتصال بالعميل", "عالية")
manager.add_task("تحديث الموقع", "منخفضة")

# عرض جميع المهام
manager.display_all_tasks()

# إكمال بعض المهام
print("\n--- إكمال المهام ---")
manager.complete_task("مراجعة البريد الإلكتروني")
manager.complete_task("الاتصال بالعميل")

# عرض المهام بعد التحديث
manager.display_all_tasks()

# عرض الملخص
manager.display_summary()

شرح الكود بالتفصيل:

التهيئة (السطور 1-7):
  • السطر 1: تعريف صنف TaskManager
  • السطر 4: دالة التهيئة تستقبل اسم المالك
  • السطر 6: قائمة فارغة لحفظ جميع المهام
  • السطر 7: قائمة فارغة للمهام المكتملة فقط
إضافة مهمة (السطور 9-17):
  • السطر 9: تعريف أسلوب add_task يستقبل اسم المهمة والأولوية (افتراضية: "متوسطة")
  • السطر 11-15: ننشئ قاموساً يمثل المهمة بثلاث معلومات
  • السطر 16: نضيف المهمة للقائمة
إكمال مهمة (السطور 19-28):
  • السطر 21: نمر على جميع المهام
  • السطر 22: نبحث عن المهمة بالاسم ونتحقق أنها غير مكتملة
  • السطر 23: نحدد المهمة كمكتملة
  • السطر 24: نضيفها لقائمة المهام المكتملة
الإحصائيات (السطور 30-49):
  • السطر 30-36: get_pending_count يعد المهام غير المكتملة
  • السطر 38-40: get_completed_count يعد المهام المكتملة
  • السطر 42-49: get_completion_rate يحسب نسبة الإنجاز (المكتملة ÷ الكل × 100)
العرض (السطور 51-72):
  • السطر 51-60: display_summary يعرض ملخصاً شاملاً ويستدعي أساليب أخرى
  • السطر 62-72: display_all_tasks يعرض قائمة مفصلة بكل المهام

6. أخطاء شائعة عند كتابة الأساليب

الخطأ 1: نسيان self
# خطأ
class Calculator:
    def add(a, b):  # نسينا self!
        return a + b

calc = Calculator()
# calc.add(5, 3)  # TypeError!

# صحيح
class Calculator:
    def add(self, a, b):  # يجب إضافة self
        return a + b

calc = Calculator()
result = calc.add(5, 3)  # يعمل بشكل صحيح
الخطأ 2: نسيان self عند الوصول للخصائص
# خطأ
class Person:
    def __init__(self, name):
        self.name = name
    
    def greet(self):
        # خطأ: name غير معرّف!
        print(f"مرحباً {name}")  # NameError!

# صحيح
class Person:
    def __init__(self, name):
        self.name = name
    
    def greet(self):
        # يجب استخدام self.name
        print(f"مرحباً {self.name}")
الخطأ 3: نسيان self عند استدعاء أسلوب آخر
# خطأ
class Math:
    def square(self, x):
        return x * x
    
    def sum_of_squares(self, a, b):
        # خطأ: يجب استخدام self.square
        return square(a) + square(b)  # NameError!

# صحيح
class Math:
    def square(self, x):
        return x * x
    
    def sum_of_squares(self, a, b):
        # استخدام self للوصول للأسلوب
        return self.square(a) + self.square(b)
ملخص الدرس
  • الأساليب (Methods) هي دوال تعيش داخل الصنف وتحدد سلوك الكائن
  • كل أسلوب يجب أن يبدأ بمعامل self
  • الأساليب يمكنها استقبال معاملات إضافية بعد self
  • الأساليب يمكنها إرجاع قيم باستخدام return
  • الأساليب يمكنها استدعاء أساليب أخرى باستخدام self.method_name()
  • للوصول لخصائص الكائن داخل الأسلوب، استخدم self.attribute
  • عند استدعاء أسلوب، لا تمرر self يدوياً - بايثون تفعل ذلك تلقائياً

الخطوة التالية

الآن بعد أن فهمنا كيف تعمل الأساليب، لنتعمق في فهم self - هذه الكلمة السحرية التي نستخدمها في كل مكان!

الدرس التالي: الكلمة المفتاحية self
المحرر الذكي

اكتب الكود وشاهد النتيجة فوراً

جرب الآن مجاناً
قناة ديف عربي

تابع أحدث الدروس والتحديثات مباشرة على واتساب

انضم الآن