🧠 فهم معامل self في بايثون: مفتاحك للتعامل مع الـ Objects

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

النقطة الأهم: self ليس كلمة محجوزة في بايثون! يمكنك استخدام أي اسم آخر (مثل this أو obj)، ولكن الاتفاقية العالمية والعرف السائد في مجتمع بايثون هو استخدام self، وهذا ما ننصحك به بشدة للحفاظ على قابلية قراءة الكود وفهمه من قبل الجميع. ✅


🔧 لماذا نحتاج إلى self؟

لنفهم الحاجة إلى self، دعنا ننظر إلى مثال بسيط. لنفترض أن لدينا كلاس Car (سيارة).

class Car:
    def start_engine(self):
        print("المحرك يعمل!")

عندما ننشئ كائنين (سيارتين) من هذا الكلاس:

my_car = Car()
your_car = Car()

السؤال هو: عندما نستدعي my_car.start_engine()، كيف تعرف الدالة start_engine() أي سيارة نقصد؟ هل هي my_car أم your_car؟

هنا يأتي دور self! 🎯 بايثون تلقائياً تمرر الكائن الذي يستدعي الدالة كأول وسيط (argument) لها. لذلك، self داخل الدالة start_engine() سيكون مرجعاً لكائن my_car عندما نكتب my_car.start_engine()، ومرجعاً لكائن your_car عندما نكتب your_car.start_engine().


✨ كيف نستخدم self داخل دوال الكلاس؟

الاستخدام الرئيسي لـ self هو الوصول إلى خصائص (attributes) ووظائف (methods) أخرى تابعة لنفس الكائن.

1. الوصول إلى الخصائص (Attributes)

داخل دالة الكلاس، نستخدم self. قبل اسم الخاصية للوصول إليها أو تعديلها.

class Student:
    def set_name(self, student_name):
        # نستخدم self لإنشاء خاصية 'name' للكائن الحالي
        self.name = student_name

    def greet(self):
        # نستخدم self للوصول إلى خاصية 'name' للكائن الحالي
        print(f"Hi, I'm {self.name}")

الآن دعنا نستخدم الكلاس:

# إنشاء كائن
student1 = Student()
student1.set_name("Ahmed") # self داخل set_name تشير إلى student1
student1.greet() # ستطبع: Hi, I'm Ahmed

# إنشاء كائن آخر
student2 = Student()
student2.set_name("Fatima") # self داخل set_name تشير الآن إلى student2
student2.greet() # ستطبع: Hi, I'm Fatima

كما ترى، self هي التي مكنت كل كائن من الاحتفاظ بقيمته الخاصة للمتغير name. 🧑‍🎓👩‍🎓


2. الوصول إلى الدوال الأخرى (Methods)

يمكننا أيضاً استخدام self لاستدعاء دالة أخرى داخل نفس الكلاس من دالة حالية.

class Calculator:
    def add(self, a, b):
        result = a + b
        self.print_result(result) # نستدعي دالة أخرى باستخدام self
        return result

    def print_result(self, value):
        print(f"The result is: {value}")

# استخدام الكلاس
my_calc = Calculator()
my_calc.add(5, 3)
# المخرجات:
# The result is: 8

🏗️ self و الدالة البانية __init__()

الدالة الخاصة __init__() هي الدالة البانية (constructor) التي تُستدعى تلقائياً عند إنشاء كائن جديد. دور self هنا حاسم جداً، فهو الوسيلة لتهيئة الخصائص الأولية للكائن الجديد.

class Book:
    def __init__(self, title, author):
        # نستخدم self لتعريف خصائص الكائن أثناء الإنشاء
        self.title = title
        self.author = author
        self.is_borrowed = False # قيمة افتراضية

    def describe(self):
        print(f"The book is: '{self.title}', and the author is: {self.author}")

# إنشاء كائن Book مع تمرير القيم لـ __init__
my_book = Book("Python Learning", "Codex Academy")
my_book.describe() # ستطبع: The book is: 'Python Learning', and the author is: Codex Academy
print(my_book.is_borrowed) # ستطبع: False

في المثال أعلاه، self.title = title تعني: "اجعل خاصية title لهذا الكائن المحدد (self) تساوي القيمة التي وصلت عبر الوسيط title".


❌ ماذا يحدث إذا نسينا self؟

إذا عرّفت دالة داخل كلاس ونسيت وضع self كأول وسيط، فستواجه خطأ عند محاولة استدعاء هذه الدالة من خلال كائن.

class Test:
    def wrong_method(): # نسيان self هنا
        print("This is a wrong method")

obj = Test()
obj.wrong_method() # ❌ سيسبب خطأ: TypeError

الخطأ سيكون لأن بايثون تحاول تلقائياً تمرير الكائن (obj) كوسيط أول للدالة، لكن الدالة wrong_method غير مهيأة لتلقي أي وسيطات.


🧩 خلاصة الدرس

  • self هو مرجع إلى الكائن الحالي الذي يستدعي الدالة. 🔄
  • هو أول وسيط في أي دالة عادية (instance method) داخل الكلاس.
  • نستخدمه للوصول إلى خصائص الكائن (self.name) واستدعاء دواله الأخرى (self.print_result()).
  • وجوده في الدالة البانية __init__ أساسي لتهيئة حالة الكائن الجديد.
  • الاتفاقية هي استخدام الاسم self، وهو ما يجب الالتزام به. 🤝