اذهب إلى المحتوى
  • 0

ماذا تفعل 'super' ضمن البايثون؟

Maram Jouriah

السؤال

أحتاج لمعرفة الفرق في استخدام 'super' ضمن ال classes 

مثل :

class Child(SomeBaseClass):
    def __init__(self):
        super(Child, self).__init__()

ما الفرق عن الحالة هذه:

class Child(SomeBaseClass):
    def __init__(self):
        SomeBaseClass.__init__(self)

 

رابط هذا التعليق
شارك على الشبكات الإجتماعية

Recommended Posts

  • 0

أولاً يمكنك في python 3 استخدام super كالتالي

class Child(SomeBaseClass):
    def __init__(self):
        super().__init__()

ثانياً في المثالين السابقين ستكون النتيجة واحدة ولكن الفرق بينهما؟

أن في الحالة الأولى لا تحتاج لكتابة SomeBaseClass وبالتالي توفر لك فائدة الوراثة من أكثر من class كالتالي

class First(object):
    def __init__(self):
        super(First, self).__init__()
        print("first")

class Second(object):
    def __init__(self):
        super(Second, self).__init__()
        print("second")

class Third(First, Second):
    def __init__(self):
        super(Third, self).__init__()
        print("third")
        

 

تم التعديل في بواسطة عبدالباسط ابراهيم
إضافة بعض المعلومات
رابط هذا التعليق
شارك على الشبكات الإجتماعية

  • 0

سأوضح في البداية هذه الدالة، بعد ذلك أجيب عن السؤال الأساسي..
أولاً:
تعيد الدالة super()‎ كائناً وسيطاً يُفوّض استدعاءات التوابع إلى صنف أب أو صنف شقيق للصنف الذي استُدعيت منه الدالة، وهذا مفيد للوصول إلى التوابع الموروثة التي أعيدت كتابتها في صنف معين.
تعريف آخر؛ ضمن صف فرعي (موروث)، يمكن الإشارة إلى الصف الأب باستخدام الدالة super، هذه الدالة تُرجع كائن مؤقت من الصنف الأب والذي يسمح بالوصول إلى جميع دواله ضمن صنفه الفرعي (الابن).
تعريف أبسط؛ هذه الدالة تجعلك قادر على الوصول إلى الدالة المعرفة في الكلاس الأب ( Superclass ) من الكلاس الابن ( Subclass ) سواء كان يوجد تضارب في الأسماء أو لا يوجد و بالتالي يصبح الكلاس الابن قادر على أن يعيد كتابة الدالة التي ورثها من الكلاس الأب و أن يصل للدالة التي ورثها من الكلاس الأب أيضاً.

فوائد استخدام الوظيفة الفائقة هي:

1. لا تحتاج إلى ذكر أو تحديد اسم الصف الأب للوصول إلى دواله، ويمكن استخدام هذه الدالة في الوراثة الفردية والمتعددة.
2. وجود هذه الدالة مفيد لعزل التغيرات ولتحقيق مفهوم قابلية إعادة استخدام الكود حيث لا توجد حاجة لإعادة كتابة الدالة بأكملها داخل الصف الابن.
3. تعتبر هذه الدالة دالة ديناميكية في بايثون (بايثون في الأساس لغة ديناميكية).

هناك 3 أشياء يجب تحديدها لاستخدام هذه الدالة:

1. الصنف المراد الذي تتم وراثته والذي نريد من الدالة super أن تشير إليه.
2. يجب أن تتطابق معطيات الدالة super والدالة التي يتم استدعاؤها.
3. يجب أن يتضمن كل تكرار للدالة على super بعد استخدامه.

هناك حالتان تُستعمل فيهما الدالة super()‎ عادةً:

تستعمل للوصول إلى الصنف الأب في شجرة أصناف ذات وراثة وحيدة (class hierarchy with single inheritance) دون الحاجة إلى تسمية الصنف مباشرة، ما يسمح للكود بأن تكون قابلة للتطوير والصيانة بشكل أفضل، وحالة الاستخدام هذه تشابه طريقة استخدام super()‎ في لغات البرمجة الأخرى.

المثال التّالي يُوضح حالة الاستخدام هذه:

class A:
    # دالة تُعيد مجموع عددين
    def add(self, x, y): 
        return x+y
# وراثة من الصنف الأب     
class B(A): 
    # دالة تُضيف العددين وتطبع العمليّة
    def add_print(self, x, y):
        # استدعاء تابع يتواجد في الصنف الأب دون تسميّة الصنف الأب بشكل صريح
        result = super().add(x, y) 
        print(f'{x}+{y}={result}')
# إنشاء كائن من الصّنف الوارث         
adder = B() 
# استدعاء دالة الإضافة والطّباعة
adder.add_print(1, 2) 
# 1+2=3
 adder.add_print(1, 5)
# 1+5=6

 

الحالة الثانية التي تُستخدم فيها هي عند الرغبة في استعمال وراثة متعددة متعاونة (cooperative multiple inheritance) في بيئة تنفيذ ديناميكية (أي أن الصّنف يمكن له أن يرث من أكثر من صنف واحد). هذه الميزة موجودة فقط في لغة بايثون ولا توجد في لغات البرمجة المجمعة (statically compiled languages) أو في لغات البرمجة التي لا تدعم سوى الوراثة الوحيدة (أي أن الصنف لا يُمكن أن يرث إلا من صنف واحد فقط). ما يُمكّن من تطبيق "تخطيطات الماسة (diamond diagrams)" عندما تحتوي أصناف آباء عدة على نفس التابع. يجب على هذا التابع أن يمتلك نفس توقيع الاستدعاء (calling signature) في جميع الحالات (لأن ترتيب الاستدعاءات يحدد في وقت التنفيذ runtime، ولأن الترتيب يتغير حسب تغير شجرة الأصناف، ولأن الترتيب يمكن له أن يشمل أصنافا شقيقة غير معلومة قبل بدء وقت التنفيذ).

يكون استدعاء الدالة super()‎ في كلتا الحالتين مشابهًا لما يلي:

class C(B):
    def method(self, arg):
		# هذا الاستدعاء مُكافئ للاستدعاء أدناه
        super().method(arg)    
		# super(C, self).method(arg)


ثانياً: العودة لسؤالك.
الدالة super تم تصميمها بشكل أساسي في بايثون من أجل الوراثة المتعددة، لكن كيف وما الفرق؟

SomeBaseClass.__init__(self) 

تعني ببساطة استدعاء الدالة __init__  من الصنف الأب، وهذه الطريقة كانت موجودة في بايثون 2، ولم تعد مستخدمة في بايثون 3.
في حين أن:

super().__init__()

means to call a bound __init__ from the parent class that follows SomeBaseClass's child class (the one that defines this method) in the instance's Method Resolution Order (MRO).
هي الطريقة المستخدمة في بايثون 3، وتعني استدعاء الدالة __init__ المربوطة بالصف الأب الذي يتبع له الصف الابن الذي تم به استدعاء هذه الدالة، حيث أن الدالة super تُرجع كائن مؤقت من الصنف الأب SomeBaseClass، مما يسمح لنا باستدعاء الدوال والخصائص الموجودة ضمنه.
يكمن الفرق بينهما في أنه في حالة الوراثة المتعددة مثلاً:

   A
   / \
  B   C
   \ /
    D

يكون لدينا أصناف ترث أصناف، ويكون لدينا __init__ تأتي بعد __init__ بناءً على ترتيب MRO. هذا يعني انه بدون super لن تتصل بـ __init__ التالية حسب ترتيب MRO، وبالتالي لن تتمكن من إعادة استخدام الكود فيه.

رابط هذا التعليق
شارك على الشبكات الإجتماعية

انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أجب على هذا السؤال...

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.

  • إعلانات

  • تابعنا على



×
×
  • أضف...