أساسيات بايثون 39: الفرق بين classmethod وstaticmethod وInstance Method ومتى تستخدم كل واحدة

الفرق بين classmethod وstaticmethod وInstance Method في بايثون

بعد تعلم معنى class وobject والفرق بين خصائص الكلاس وخصائص الكائن، ستبدأ بملاحظة أن الدوال داخل الكلاس ليست كلها من النوع نفسه. بعض الدوال تعمل على بيانات كائن محدد، وبعضها يحتاج إلى الكلاس نفسه، وبعضها لا يحتاج إلى الكائن ولا إلى الكلاس أصلًا.

هنا تظهر ثلاثة أنواع مهمة من Methods في بايثون: Instance Method وClass Method وStatic Method. والفرق بينها يرتبط مباشرة بالسؤال: ما الذي تحتاج الدالة للوصول إليه؟ هل تحتاج بيانات object عبر self؟ أم بيانات class عبر cls؟ أم أنها مجرد وظيفة مرتبطة منطقيًا بالكلاس ولا تحتاج أيًا منهما؟

في الدرس 39 من أساسيات بايثون سنبني كلاس Product ونستخدم الأنواع الثلاثة في مثال واحد. سنفهم الفرق بين self وcls، ومتى نستخدم @classmethod و@staticmethod، وكيف نصنع Alternative Constructor، ولماذا استخدام cls أفضل من كتابة اسم الكلاس مباشرة عند دعم الوراثة.

{alertInfo} الفكرة ببساطة: استخدم Instance Method عندما تحتاج إلى بيانات object محدد، وClass Method عندما تحتاج إلى class نفسها أو تريد إنشاء object بطريقة بديلة، وStatic Method عندما تكون العملية مرتبطة منطقيًا بالكلاس لكنها لا تحتاج إلى self ولا cls.

{getToc} $title={محتوى المقال}

ما هي Method داخل class؟

الـMethod هي دالة تُعرّف داخل class. الفرق الحقيقي بينها وبين Function عادية لا يقتصر على مكان الكتابة؛ فعند الوصول إلى بعض أنواع Methods من object أو class، تقوم بايثون بعملية ربط Binding تحدد ما الذي يُمرر تلقائيًا كأول وسيط.

لنبدأ بكلاس بسيط:

class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price

    def show_info(self):
        print(self.name, self.price)

الدالة show_info() هنا Instance Method؛ لأنها تستقبل self وتعمل على بيانات الكائن الحالي.

الأنواع الثلاثة بسرعة

النوع الصيغة الشائعة ما الذي يصل تلقائيًا؟ الاستخدام الأساسي
Instance Method def method(self) الكائن الحالي قراءة أو تعديل بيانات object.
Class Method @classmethod ثم def method(cls) الكلاس التعامل مع بيانات class أو إنشاء كائنات بطريقة بديلة.
Static Method @staticmethod ثم def method(...) لا شيء وظيفة مرتبطة منطقيًا بالكلاس ولا تحتاج object أو class.
مقارنة Instance Method وClass Method وStatic Method في بايثون

أولًا: ما هي Instance Method؟

Instance Method هي النوع الذي استخدمناه في الدروس السابقة غالبًا دون تسميته بهذا الاسم. تستقبل object الحالي كأول parameter، والمتعارف عليه أن نسمي هذا parameter باسم self.

class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price

    def show_price(self):
        print(self.price)

عندما ننشئ كائنًا:

product = Product("Keyboard", 80)

product.show_price()

الناتج:

80

لم نكتب self داخل الأقواس عند الاستدعاء. بايثون تربط الـmethod بالكائن product وتمرره تلقائيًا كأول وسيط.

ما معنى self في بايثون؟

self تشير إلى object الحالي الذي استدعيت منه الـmethod. إذا كان لديك منتجان، فإن كل استدعاء يعمل على بيانات الكائن الخاص به.

class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price

    def show_price(self):
        print(self.name, self.price)


product1 = Product("Keyboard", 80)
product2 = Product("Mouse", 30)

product1.show_price()
product2.show_price()

الناتج:

Keyboard 80
Mouse 30

في الاستدعاء الأول تشير self إلى product1، وفي الثاني تشير إلى product2.

هل كلمة self كلمة محجوزة؟

لا. تستطيع من الناحية التقنية استخدام اسم آخر، لكن self هي الاتفاقية القياسية التي يتوقعها مبرمجو بايثون، لذلك لا يوجد سبب عملي لتغييرها في الكود العادي.

متى نستخدم Instance Method؟

استخدمها عندما تحتاج العملية إلى حالة object محدد، مثل السعر أو الاسم أو الرصيد أو حالة الطلب.

مثال لحساب السعر بعد الخصم:

class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price

    def discounted_price(self, discount):
        return self.price * (1 - discount)


product = Product("Keyboard", 80)

print(product.discounted_price(0.10))

الدالة تحتاج إلى self.price الخاص بهذا المنتج، لذلك Instance Method هي الاختيار الطبيعي.

هل يمكن استدعاء Instance Method من class نفسها؟

يمكن الوصول إلى الدالة من class، لكن عند استدعائها بهذه الطريقة لا يوجد object مرتبط تلقائيًا، لذلك يجب تمرير الكائن صراحة:

product = Product("Keyboard", 80)

Product.show_price(product)

هذا يعمل، لكنه ليس الأسلوب المعتاد عند التعامل مع Instance Method. الأسلوب الطبيعي والأوضح:

product.show_price()

ثانيًا: ما هي Class Method؟

Class Method هي method ترتبط بالكلاس بدل ارتباطها بكائن محدد. نكتب فوقها decorator باسم @classmethod، ويكون أول parameter عادةً cls.

class Product:
    tax_rate = 0.10

    @classmethod
    def show_tax_rate(cls):
        print(cls.tax_rate)

نستدعيها من class:

Product.show_tax_rate()

الناتج:

0.1

هنا تمرر بايثون Product تلقائيًا إلى cls.

ما معنى cls في بايثون؟

cls تشير إلى class التي تم استدعاء Class Method منها. كما أن self تمثل object حاليًا، فإن cls تمثل class الحالية.

الاسم cls ليس كلمة محجوزة أيضًا، لكنه الاسم المتعارف عليه، واستخدامه يجعل الكود واضحًا.

الفرق بين self وcls في بايثون داخل الكلاسات

الفرق بين self وcls

النقطة self cls
تشير إلى Object محدد. Class.
تستخدم في Instance Method. Class Method.
الوصول إلى Instance Attributes مثل self.price. Class Attributes مثل cls.tax_rate.
تُمرر تلقائيًا؟ نعم عند استدعاء method من object. نعم عند استدعاء classmethod.

تعديل Class Attribute باستخدام classmethod

لنفترض أن كل المنتجات تشترك في نسبة ضريبة افتراضية:

class Product:
    tax_rate = 0.10

    def __init__(self, name, price):
        self.name = name
        self.price = price

    @classmethod
    def set_tax_rate(cls, rate):
        cls.tax_rate = rate

يمكننا تغيير القيمة المشتركة:

Product.set_tax_rate(0.15)

print(Product.tax_rate)

الناتج:

0.15

هذه العملية تخص class ككل، لا منتجًا واحدًا، لذلك classmethod مناسبة.

مثال يجمع self وcls في الكلاس نفسه

class Product:
    tax_rate = 0.10

    def __init__(self, name, price):
        self.name = name
        self.price = price

    def final_price(self):
        return self.price * (1 + self.tax_rate)

    @classmethod
    def set_tax_rate(cls, rate):
        cls.tax_rate = rate

ثم:

product = Product("Keyboard", 100)

print(product.final_price())

Product.set_tax_rate(0.15)

print(product.final_price())

Instance Method تحسب سعر object محدد، بينما Class Method تغير إعدادًا مشتركًا على مستوى class.

أقوى استخدام لـclassmethod: Alternative Constructor

أحيانًا لا تأتي بيانات إنشاء object بالشكل المتوقع في __init__. مثلًا كلاس المنتج يستقبل الاسم والسعر منفصلين:

class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price

لكن لديك نص بهذا الشكل:

Keyboard,80

يمكنك إنشاء Class Method تحول النص إلى object.

class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price

    @classmethod
    def from_string(cls, text):
        name, price = text.split(",")

        return cls(
            name,
            float(price)
        )

الاستخدام:

product = Product.from_string(
    "Keyboard,80"
)

print(product.name)
print(product.price)

الناتج:

Keyboard
80.0
استخدام classmethod كـ Alternative Constructor في بايثون

لماذا يسمى Alternative Constructor؟

لأنك وفرت مسارًا إضافيًا لإنشاء object بدل إجبار المستخدم على تمرير البيانات بصيغة واحدة فقط.

المسار الأساسي:

Product("Keyboard", 80)

المسار البديل:

Product.from_string("Keyboard,80")

كلاهما ينتج object من Product، لكن مصدر البيانات مختلف.

هل يمكن إنشاء أكثر من constructor في بايثون؟

إذا قصدت كتابة عدة دوال باسم __init__ داخل class واحدة كما يحدث مع Constructor Overloading في بعض اللغات، فهذا ليس الأسلوب المعتاد في بايثون؛ آخر تعريف للاسم نفسه سيحل محل السابق.

بدل ذلك، تعتبر Class Methods المسماة مثل from_string() أو from_dict() أو from_file() طريقة واضحة لإنشاء بدائل للإنشاء.

Alternative Constructor من Dictionary

class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price

    @classmethod
    def from_dict(cls, data):
        return cls(
            data["name"],
            data["price"]
        )

الاستخدام:

data = {
    "name": "Mouse",
    "price": 30
}

product = Product.from_dict(data)

print(product.name)

لماذا نكتب cls(...) بدل Product(...)؟

قد يبدو هذا السطر:

return Product(name, price)

أنه يؤدي الغرض، لكنه يربط Class Method باسم Product صراحة. الأفضل داخل Alternative Constructor عادةً:

return cls(name, price)

السبب يظهر بوضوح مع الوراثة.

كيف تتصرف classmethod مع الوراثة؟

لنفترض وجود كلاس ابن:

class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price

    @classmethod
    def from_string(cls, text):
        name, price = text.split(",")
        return cls(name, float(price))


class DigitalProduct(Product):
    pass

الآن:

item = DigitalProduct.from_string(
    "Ebook,12"
)

print(type(item))

ستحصل على object من DigitalProduct؛ لأن cls تشير إلى الكلاس الذي تم الاستدعاء منه.

هذه نقطة مهمة: استخدام cls يجعل الـclassmethod أكثر توافقًا مع الوراثة من كتابة اسم الكلاس الأب مباشرة.

ثالثًا: ما هي Static Method؟

Static Method هي دالة موضوعة داخل class لكنها لا تستقبل object تلقائيًا ولا class تلقائيًا. نستخدم decorator باسم @staticmethod.

class Product:
    @staticmethod
    def is_valid_price(price):
        return price >= 0

الاستخدام:

print(
    Product.is_valid_price(50)
)

print(
    Product.is_valid_price(-5)
)

الناتج:

True
False

لماذا لم نستخدم self أو cls؟

لأن التحقق من كون القيمة غير سالبة لا يحتاج إلى معرفة object محدد، ولا يحتاج إلى قراءة أو تعديل حالة class.

الدالة تحتاج فقط إلى القيمة price التي مررناها لها.

متى نستخدم staticmethod؟

استخدمها عندما تكون الوظيفة مرتبطة منطقيًا بالمفهوم الذي تمثله class، لكن تنفيذها لا يعتمد على بيانات instance أو class.

مثال:

class Product:
    @staticmethod
    def normalize_name(name):
        return name.strip().title()

ثم:

print(
    Product.normalize_name(
        "  wireless mouse  "
    )
)

الناتج:

Wireless Mouse

هل staticmethod مجرد Function عادية داخل class؟

من ناحية أنها لا تحصل على self أو cls تلقائيًا، هي قريبة من Function عادية. فائدتها التنظيمية هي أن اسمها يوجد داخل namespace الخاص بالكلاس لأنها مرتبطة منطقيًا به.

لكن لا تجعل كل دالة مساعدة staticmethod تلقائيًا. إذا كانت الوظيفة عامة ولا تنتمي بوضوح إلى class، فقد يكون وضعها كFunction مستقلة في module أوضح.

هل يمكن استدعاء staticmethod من object؟

نعم، هذا يعمل:

product = Product()

print(
    product.is_valid_price(20)
)

لكن إذا كانت الـmethod لا تحتاج إلى object، فالاستدعاء عبر class يكون غالبًا أوضح:

Product.is_valid_price(20)

هل يمكن استدعاء classmethod من object؟

نعم، يمكن ذلك أيضًا:

product = Product("Keyboard", 80)

product.set_tax_rate(0.20)

لكن لأن العملية تتعلق بالكلاس نفسه، فإن:

Product.set_tax_rate(0.20)

يوضح القصد بصورة أفضل للقارئ.

مثال واحد يجمع الأنواع الثلاثة

class Product:
    tax_rate = 0.10

    def __init__(self, name, price):
        self.name = name
        self.price = price

    # Instance Method
    def final_price(self):
        return self.price * (
            1 + self.tax_rate
        )

    # Class Method
    @classmethod
    def set_tax_rate(cls, rate):
        cls.tax_rate = rate

    # Alternative Constructor
    @classmethod
    def from_string(cls, text):
        name, price = text.split(",")

        return cls(
            name,
            float(price)
        )

    # Static Method
    @staticmethod
    def is_valid_price(price):
        return price >= 0

ثم:

product = Product.from_string(
    "Keyboard,100"
)

print(
    product.final_price()
)

Product.set_tax_rate(0.15)

print(
    product.final_price()
)

print(
    Product.is_valid_price(-20)
)

لاحظ كيف يقوم كل نوع بدور مختلف بدل اختيار decorator بصورة عشوائية.

كيف أقرر أي نوع من Methods أستخدم؟

اسأل هذه الأسئلة بالترتيب:

  1. هل أحتاج إلى قراءة أو تعديل بيانات object مثل self.price؟ استخدم Instance Method.
  2. هل أحتاج إلى class أو Class Attributes، أو أريد Alternative Constructor؟ استخدم Class Method.
  3. لا أحتاج إلى object ولا class، لكن الوظيفة مرتبطة منطقيًا بالكلاس؟ قد تكون Static Method مناسبة.
  4. لا توجد علاقة حقيقية بالكلاس؟ قد تكون Function مستقلة أفضل.

جدول اختيار سريع

المطلوب الاختيار الأنسب غالبًا
حساب يعتمد على سعر منتج محدد Instance Method
تغيير إعداد مشترك لكل المنتجات Class Method
إنشاء Product من نص أو Dictionary Class Method
التحقق من صيغة قيمة بدون بيانات object أو class Static Method أو Function مستقلة حسب ارتباطها بالكلاس.
دالة عامة لا تخص Product Function مستقلة.

هل __init__ هي Instance Method؟

__init__ تستقبل self وتعمل على object الذي تم إنشاؤه، ولذلك هي Instance Method خاصة تستخدم لتهيئة الكائن بعد إنشائه.

class Product:
    def __init__(self, name):
        self.name = name

وعندما تكتب:

product = Product("Keyboard")

تتولى آلية إنشاء الكائن في بايثون تمرير object الجديد إلى __init__، ولا تكتب self بنفسك.

خطأ شائع 1: نسيان self في Instance Method

الكود التالي:

class Product:
    def show_name():
        print("Product")

ثم:

product = Product()
product.show_name()

قد يؤدي إلى TypeError؛ لأن بايثون تمرر object تلقائيًا بينما الدالة لم تجهز parameter لاستقباله.

الصحيح:

class Product:
    def show_name(self):
        print("Product")

خطأ شائع 2: كتابة self داخل staticmethod بلا داعٍ

class Product:
    @staticmethod
    def is_valid(self, price):
        return price >= 0

@staticmethod لا تمرر object تلقائيًا. وجود parameter باسم self هنا لا يحوله سحريًا إلى object؛ سيكون مجرد parameter عادي يجب تمريره يدويًا.

إذا لم تحتج object:

class Product:
    @staticmethod
    def is_valid(price):
        return price >= 0

خطأ شائع 3: استخدام classmethod لعملية تخص object واحدًا

إذا كانت العملية تحتاج price الخاص بكل منتج، فلا تجعلها Class Method ثم تبدأ بتمرير object أو السعر حول الكود بلا سبب.

هذا أوضح:

class Product:
    def __init__(self, price):
        self.price = price

    def final_price(self):
        return self.price * 1.10

القاعدة: عندما تكون البيانات جزءًا من حالة object، دع Instance Method تعمل عليها مباشرة عبر self.

خطأ شائع 4: كتابة اسم class داخل Alternative Constructor

بدل:

@classmethod
def from_string(cls, text):
    name, price = text.split(",")

    return Product(
        name,
        float(price)
    )

اكتب:

@classmethod
def from_string(cls, text):
    name, price = text.split(",")

    return cls(
        name,
        float(price)
    )

هذا يحافظ على السلوك الصحيح عندما ترث class أخرى من Product وتستخدم نفس الـclassmethod.

الفرق بين self وcls في بايثون داخل الكلاسات

خطأ شائع 5: استخدام staticmethod فقط لتقليل كتابة self

عدم رغبتك في كتابة self ليس سببًا لاستخدام Static Method. اختر النوع بحسب البيانات التي تحتاجها الدالة.

إذا كانت العملية تحتاج object حقيقيًا، فاستخدام Instance Method يجعل الاعتماد واضحًا ويمنع تمرير بيانات object يدويًا بصورة مشتتة.

خطأ شائع 6: تحويل كل Function مساعدة إلى staticmethod

وجود class في الملف لا يعني أن جميع الوظائف يجب أن تدخل داخلها. إذا كانت Function لا تعتمد على الكلاس ولا ترتبط به كمفهوم، اتركها خارج class.

def format_currency(value):
    return f"${value:.2f}"

قد تكون هذه وظيفة عامة يستخدمها أكثر من نوع في البرنامج، فلا توجد فائدة من حبسها داخل Product بلا سبب.

Instance Method وClass Attribute معًا

Instance Method تستطيع الوصول إلى Class Attribute عبر object:

class Product:
    tax_rate = 0.10

    def __init__(self, price):
        self.price = price

    def final_price(self):
        return self.price * (
            1 + self.tax_rate
        )

لكن تذكر أن self هنا ما زالت تشير إلى object. استخدام Class Attribute داخل Instance Method لا يحولها إلى Class Method.

هل classmethod تستطيع الوصول إلى Instance Attributes؟

ليس لديها object محدد تلقائيًا. cls تشير إلى class ولا تعرف أي instance تريد.

هذا المفهوم مهم:

class Product:
    def __init__(self, price):
        self.price = price

    @classmethod
    def show_price(cls):
        # أي Product تقصد؟
        pass

إذا كانت العملية تحتاج سعر object معين، يجب أن تكون Instance Method أو أن تمرر object صراحة لسبب واضح، وغالبًا الأول أبسط.

هل staticmethod تستطيع الوصول إلى Class Attributes؟

لا تحصل على cls تلقائيًا. تستطيع تقنيًا كتابة اسم class داخلها، لكن إذا كانت الوظيفة تعتمد فعليًا على حالة class، فهذا مؤشر قوي على أن classmethod قد تكون التصميم الأنسب.

مثال غير مرن:

class Product:
    tax_rate = 0.10

    @staticmethod
    def show_tax():
        print(Product.tax_rate)

الأوضح:

class Product:
    tax_rate = 0.10

    @classmethod
    def show_tax(cls):
        print(cls.tax_rate)

ماذا يحدث فعليًا عند ربط Instance Method؟

لفهم الفكرة، قارن هذين الاستدعاءين:

product.show_price()

والصيغة المباشرة من class:

Product.show_price(product)

في الاستخدام المعتاد تقوم بايثون بربط method بالكائن عند الوصول إليها عبر instance، لذلك لا تمرر self بنفسك.

وماذا يحدث مع classmethod؟

عند:

Product.show_tax_rate()

يتم تمرير class نفسها كأول وسيط إلى cls. وإذا استدعيت inherited classmethod من subclass، تكون cls هي subclass التي تم الاستدعاء منها.

أما staticmethod فلا يوجد Binding لـself أوcls

لذلك هذه الدالة:

class Calculator:
    @staticmethod
    def add(a, b):
        return a + b

تستقبل فقط القيم التي مررتها صراحة:

print(
    Calculator.add(4, 5)
)

مثال تطبيقي أقرب لمشروع حقيقي

سننشئ كلاس لإدارة منتج. سنجعل Instance Method تحسب السعر النهائي، Class Method تغير الضريبة، Class Method أخرى تنشئ المنتج من CSV line، وStatic Method تتحقق من صحة SKU.

class Product:
    tax_rate = 0.10

    def __init__(self, sku, name, price):
        if not self.is_valid_sku(sku):
            raise ValueError("SKU غير صالح")

        self.sku = sku
        self.name = name
        self.price = float(price)

    def final_price(self):
        return self.price * (
            1 + self.tax_rate
        )

    @classmethod
    def set_tax_rate(cls, rate):
        if rate < 0:
            raise ValueError(
                "نسبة الضريبة لا يمكن أن تكون سالبة"
            )

        cls.tax_rate = rate

    @classmethod
    def from_csv_line(cls, line):
        sku, name, price = line.split(",")

        return cls(
            sku.strip(),
            name.strip(),
            float(price)
        )

    @staticmethod
    def is_valid_sku(sku):
        return (
            isinstance(sku, str)
            and len(sku.strip()) >= 3
        )

الاستخدام:

product = Product.from_csv_line(
    "KB100, Keyboard, 80"
)

print(product.name)
print(product.final_price())

Product.set_tax_rate(0.15)

print(product.final_price())

print(
    Product.is_valid_sku("A")
)

كل method هنا لها سبب واضح لاختيار نوعها. هذه هي الفكرة الأهم في الدرس.

متى تكون staticmethod أفضل من classmethod؟

إذا كان التحقق أو الحساب لا يعتمد على حالة الكلاس، فلا تحتاج إلى cls.

مثل:

@staticmethod
def is_valid_sku(sku):
    return len(sku.strip()) >= 3

أما إذا أصبحت قاعدة التحقق تعتمد على Class Attribute:

class Product:
    min_sku_length = 3

    @classmethod
    def is_valid_sku(cls, sku):
        return (
            len(sku.strip())
            >= cls.min_sku_length
        )

هنا أصبحت Class Method منطقية لأن الدالة تعتمد على حالة الكلاس.

متى تكون Function خارج class أفضل من staticmethod؟

إذا كانت الوظيفة لا تخص مفهوم Product تحديدًا وتستخدم في أجزاء كثيرة، فFunction مستقلة قد تكون أكثر وضوحًا.

لا تستخدم class كصندوق تجمع داخله كل الدوال. الهدف من OOP هو تنظيم المسؤوليات، وليس نقل كل Function إلى داخل class.

تمرين عملي

أنشئ class باسم Student تحتوي على:

  • Instance Attributes باسم name وscore.
  • Class Attribute باسم passing_score وقيمتها 60.
  • Instance Method باسم is_passed().
  • Class Method باسم set_passing_score().
  • Class Method باسم from_string() تقرأ نصًا مثل "Ali,85".
  • Static Method باسم is_valid_score() تتحقق أن الدرجة بين 0 و100.

حل مقترح

class Student:
    passing_score = 60

    def __init__(self, name, score):
        if not self.is_valid_score(score):
            raise ValueError("درجة غير صالحة")

        self.name = name
        self.score = score

    def is_passed(self):
        return (
            self.score
            >= self.passing_score
        )

    @classmethod
    def set_passing_score(cls, score):
        if not cls.is_valid_score(score):
            raise ValueError("درجة غير صالحة")

        cls.passing_score = score

    @classmethod
    def from_string(cls, text):
        name, score = text.split(",")

        return cls(
            name.strip(),
            float(score)
        )

    @staticmethod
    def is_valid_score(score):
        return 0 <= score <= 100

ثم جرّب:

student = Student.from_string(
    "Ali,85"
)

print(student.is_passed())

Student.set_passing_score(90)

print(student.is_passed())

قائمة فحص لفهم الدرس

  • هل تعرف أن Instance Method تستقبل self؟
  • هل تعرف أن self تشير إلى object الحالي؟
  • هل تعرف أن Class Method تستخدم @classmethod وتستقبل cls؟
  • هل تعرف أن cls تشير إلى class التي تم الاستدعاء منها؟
  • هل تستطيع استخدام classmethod كـAlternative Constructor؟
  • هل تعرف لماذا return cls(...) أفضل من كتابة اسم الكلاس مباشرة في هذا السياق؟
  • هل تعرف أن Static Method لا تستقبل self أو cls تلقائيًا؟
  • هل تستطيع تحديد متى تكون Function مستقلة أوضح من staticmethod؟

روابط داخلية مفيدة من بايثون العرب

مصادر رسمية للتوسع

الخلاصة

الفرق بين Instance Method وClass Method وStatic Method يصبح بسيطًا عندما تحدد نوع البيانات التي تحتاجها العملية. Instance Method تعمل على object محدد وتحصل على self. Class Method ترتبط بالكلاس وتحصل على cls. أما Static Method فلا تحصل تلقائيًا على object أو class.

استخدم Instance Method للعمليات التي تعتمد على حالة الكائن مثل self.price. استخدم @classmethod للعمليات المتعلقة بحالة class أو لإنشاء Alternative Constructors مثل from_string(). واستخدم @staticmethod لوظيفة مرتبطة منطقيًا بالكلاس لكنها لا تحتاج إلى self أو cls.

الأهم ألا تختار النوع بناءً على الشكل أو الرغبة في تجنب كتابة self. اختيار Method الصحيحة يجعل مسؤوليات الكلاس أوضح، ويجعل الكود أسهل في التوسع والوراثة والصيانة.

{alertSuccess} القاعدة المهمة: بيانات object تعني غالبًا self، وبيانات class تعني غالبًا cls، وإذا لم تحتج أيًا منهما ففكر في staticmethod أو Function مستقلة حسب مكان المسؤولية المنطقي.

أسئلة شائعة

ما الفرق بين classmethod وstaticmethod في بايثون؟

Class Method تستقبل class تلقائيًا في parameter يسمى عادةً cls، ولذلك تستطيع التعامل مع Class Attributes أو إنشاء objects. أما Static Method فلا تستقبل class ولا object تلقائيًا، وتعمل مثل Function مرتبطة تنظيميًا بالكلاس.

ما الفرق بين Instance Method وClass Method؟

Instance Method تستقبل object الحالي عبر self وتعمل على بياناته، بينما Class Method تستقبل class عبر cls وتتعامل مع مستوى الكلاس بدل object محدد.

ما الفرق بين self وcls في بايثون؟

self تشير إلى instance محددة، أما cls فتشير إلى class التي تم استدعاء Class Method منها.

متى أستخدم classmethod؟

استخدمها عندما تحتاج إلى بيانات أو إعدادات class، أو عندما تريد توفير طريقة بديلة لإنشاء object مثل from_string() أو from_dict().

متى أستخدم staticmethod؟

عندما تكون الوظيفة مرتبطة منطقيًا بالكلاس، لكنها لا تحتاج إلى بيانات object ولا إلى حالة class.

هل staticmethod تحتاج self؟

لا. بايثون لا تمرر self أو cls تلقائيًا إلى Static Method.

هل classmethod تحتاج إلى إنشاء object أولًا؟

لا. يمكنك استدعاؤها مباشرة من class مثل Product.set_tax_rate().

هل يمكن استدعاء Method بدون إنشاء object؟

Class Methods وStatic Methods يمكن استدعاؤهما مباشرة من class. أما Instance Method فتحتاج عادةً إلى object لأنها تعمل على instance محددة.

ما معنى Alternative Constructor في بايثون؟

هي طريقة إضافية لإنشاء object بصيغة مختلفة عن الاستدعاء المباشر المعتاد، وغالبًا تنفذ باستخدام @classmethod بأسماء مثل from_string() وfrom_dict().

لماذا نستخدم cls بدل اسم class داخل classmethod؟

لأن cls تشير إلى class التي تم الاستدعاء منها، بما في ذلك subclasses، ولذلك تجعل الكود أكثر مرونة مع الوراثة.

هل يمكن استدعاء staticmethod من object؟

نعم، لكن إذا لم تكن بحاجة إلى object فإن استدعاءها من class يكون عادةً أوضح في التعبير عن القصد.

هل يمكن استدعاء classmethod من object؟

نعم، لكنها تبقى مرتبطة بالكلاس، ولذلك يكون استدعاؤها من class أوضح غالبًا عندما تكون العملية تخص class كلها.

هل كل دالة لا تستخدم self يجب أن تكون staticmethod؟

لا. إذا كانت الوظيفة لا ترتبط منطقيًا بالكلاس، فقد تكون Function مستقلة خارج class أكثر وضوحًا وتنظيمًا.

هل __init__ هي Instance Method؟

نعم، هي method خاصة تستقبل self وتستخدم لتهيئة object بعد إنشائه.

هل يمكن عمل أكثر من constructor في بايثون؟

لا تعتمد على تعريف عدة دوال __init__ بالاسم نفسه. بدلًا من ذلك، استخدم Class Methods كـAlternative Constructors عندما تحتاج طرق إنشاء متعددة.

إرسال تعليق

أحدث أقدم