الوراثة المتعددة وأصناف mixin

13.5 الوراثة المتعددة وأصناف mixin

أهداف التعلم

في نهاية هذا القسم، ينبغي أن تكون قادرًا على

  • إنشاء صنف يرث من عدة أصناف أساسية.
  • تحديد مشكلة الماسة ضمن الوراثة المتعددة.
  • إنشاء صنف mixin لإضافة وظائف إلى صنف فرعي.

أساسيات الوراثة المتعددة

الوراثة المتعددة (Multiple inheritance) نوع من الوراثة يرث فيه صنف واحد من عدة أصناف. يحتوي الصنف الذي يرث من عدة أصناف على جميع الأصناف الأساسية المدرجة في قائمة الوراثة لتعريف الصنف. مثال: class SubClass(SuperClass_1, SuperClass_2).

نقطة تحقق

تنظيم الوراثة المتعددة

مفاهيم تطبيقية

تطبيق الوراثة المتعددة

تأمل البرنامج التالي:

    class A:
      def __init__(self, a_attr=2):
        self.a_attr = a_attr

    class B:
      def __init__(self, b_attr=4):
        self.b_attr = b_attr

    class C(A, B):
      def __init__(self, a_attr=5, b_attr=10, c_attr=20):
        A.__init__(self, a_attr)
        B.__init__(self, b_attr)
        self.c_attr = c_attr

    b_inst = B(2)
    c_inst = C(1, 2)
1.
ما قيمة c_inst.a_attr؟
  1. 1
  2. 5
  3. Error
2.
ما قيمة c_inst.c_attr؟
  1. 2
  2. 20
  3. Error
3.
ما قيمة b_inst.a_attr؟
  1. 2
  2. 4
  3. Error

مشكلة الماسة وأصناف mixin

ينبغي تطبيق الوراثة المتعددة (Multiple inheritance) بحذر. تحدث مشكلة الماسة (diamond problem) عندما يرث صنف من عدة أصناف تشترك في صنف أساسي مشترك. مثال: Dessert و BakedGood كلاهما يرث من Food، و ApplePie يرث من Dessert و BakedGood.

مخطط مفاهيمي يوضح تسلسلًا هرميًا للتصنيف. يظهر 'ApplePie' كنوع فرعي لكل من 'Dessert' و 'BakedGood'، واللذان بدورهما نوعان فرعيان من 'Food'.
شكل 13.2 مشكلة الماسة. إذا كان كل من
Dessert
و
BakedGood
يعيد تعريف تابعًا لـ
Food
، فإن التابع المُعاد تعريفه لـ
Food
الذي يرثه
ApplePie
يكون غامضًا. لذلك، ينبغي تجنب الوراثة ذات الشكل الماسي.

تعزز أصناف mixin (Mixin classes) النمطية ويمكنها حل مشكلة الماسة. صنف mixin:

  • ليس له صنف أساسي
  • يحتوي على سمات وتوابع لإضافتها إلى صنف فرعي
  • لا يُنشأ منه مثيل (مثال: إذا كان لدينا صنف MyMixin، لا ينبغي استخدام my_inst = MyMixin() أبدًا.)

تُستخدم أصناف mixin في الوراثة المتعددة لإضافة وظائف إلى صنف فرعي دون إضافة تعقيدات الوراثة.

مفاهيم تطبيقية

إنشاء صنف mixin

الشِفرة التالية ليست صحيحة، حيث ليست جميع النباتات آكلة للحوم. اتبع المبرمج خلال تعديلاته لتحسين البرنامج. ملاحظة: Rose و Pitcher و VenusFlyTrap تمثل نباتات تؤدي جميعها عملية التمثيل الضوئي. Pitcher و VenusFlyTrap تمثل نباتات آكلة للحوم أيضًا ويمكنها أن تأكل.

تُستخدم تعليمة pass في بايثون للإشارة إلى أن الشِفرة ستُكتب لاحقًا وتمنع أخطاء معينة قد تحدث إذا لم تُكتب شِفرة أو استُخدم تعليق بدلاً من ذلك.

    class Plant:
      def photosynth(self):
        print("Photosynthesizing")

      def eat(self):
        print("Eating")

    class Rose(Plant):
      pass

    class Pitcher(Plant):
      pass
    
    class VenusFlyTrap(Plant):
      pass
4.
أي تعديل مناسب؟
  1. انقل eat() إلى صنف مختلف.
  2. أزل Plant كصنف أساسي.
5.
عدَّل المبرمج الشِفرة على النحو التالي. كيف يمكن تحسين البرنامج؟
class Plant:
  def photosynth(self):
    print("Photosynthesizing")

class Rose(Plant):
  pass

class Pitcher(Plant):
  def eat(self):
    print("Eating")

class VenusFlyTrap(Plant)
  def eat(self):
    print("Eating")
  1. انقل photosynth() إلى Rose.
  2. أزل تكرار eat().
6.
يقوم المبرمج بتعديل الشِفرة لإنشاء صنف mixin يحتوي على eat(). ما هو اسم الصنف الأكثر ملاءمة لصنف mixin، ليحل محل X؟
class Plant:
  def photosynth(self):
    print("Photosynthesizing")

class X:
  def eat(self):
    print("Eating")

class Rose(Plant):
  pass

class Pitcher(Plant, X):
  pass

class VenusFlyTrap(Plant, X)
  pass
  1. CarnivClass
  2. CarnivMixin

جرّب بنفسك

حل مشكلة الماسة باستخدام صنف mixin

يمثل البرنامج أدناه الوراثة المتعددة ويعاني من مشكلة الماسة. عدّل البرنامج لاستخدام صنف mixin، OnlineMixin. OnlineMixin:

  • يحل محل OnlineShop.
  • هو صنف أساسي لـ FoodFast.
  • يحتوي على تابع واحد، process_online()، يطبع "Connecting to server" ويُستدعى بواسطة FoodFast في تابعه process_order().

ينبغي أن يطابق الناتج التالي:

    Processing meal order
    Connecting to server
    Enjoy your FoodFast order