التعددية الشكلية (Polymorphism) هي القدرة على استخدام واجهة موحدة لعدة أشكال مختلفة، مثل أنواع البيانات أو الأصناف . هذا يسمح للدوال باستخدام كيانات من أنواع مختلفة.
بالنسبة للبرامج الكائنية في بايثون، هذا يعني أنه يمكن استخدام كائن معين ينتمي إلى صنف مُعيَّن كما لو كان ينتمي إلى صنف مختلف. تسمح التعددية الشكلية بكتابة شيفرات مرنة ومجرّدَة وسهلة التوسيع والصيانة.
سوف تتعلم في هذا الدرس كيفية تطبيق التعددية الشكلية على أصناف بايثون.
ما هي التعددية الشكلية؟
التعددية الشكلية هي إحدى السمات الأساسية للأصناف في بايثون، وتُستخدَم عندما تكون هناك توابع لها نفس الأسماء في عدة أصناف، أو أصناف فرعية. يسمح ذلك للدوال باستخدام كائنات من أيٍّ من تلك الأصناف والعمل عليها دون الاكتراث لنوعها.
يمكن تنفيذ التعددية الشكلية عبر [الوراثة](رابط المقالة السابقة)، أو باستخدام توابعِ الأصناف الفرعية، أو إعادة تعريفها (overriding).
يستخدم بايثون نظام أنواع (typing) خاص، يسمى «نظام التحقق من الأنواع: البطة نموذجًا» (Duck Typing)، وهو حالة خاصة من أنظمة التحقق من الأنواع الديناميكية (Dynamic Typing). يستخدم هذا النظامُ التعدُّديةَ الشكلية، بما في ذلك الربط المتأخر، والإيفاد الديناميكي. يعتمد هذا النظام على «نموذج البطة» بناءً على اقتباسٍ للكاتب جيمس ويتكومب رايلي:
اقتباس"عندما أرى طائرًا يمشي مثل بطة، ويسبح مثل بطة، وصوته كصوت البطة، فسأعدُّ هذا الطير بطةً"
خُصِّص هذا المفهوم من قبل مهندس الحاسوب الإيطالي أليكس مارتيلي (Alex Martelli) في رسالة إلى مجموعة comp.lang.python، يقوم نظام التحقق من الأنواع هذا الذي يعتمد البطة نموذجًا على تعريف الكائن من منظور ملاءمة الغرض الذي أُنشِئ لأجله. عند استخدام نظام أنواع عادي، فإنّ ملاءمة الكائن لغرض مُعيَّن يتحدد بنوع الكائن فقط، ولكن في نموذج البطة، يَتحدَّد ذلك بوجود التوابع والخاصيات الضرورية لذلك الغرض بدلًا من النوع الحقيقي للكائن. بمعنى آخر، إذا أردت أن تعرف إن كان الكائن بطةً أم لا، فعليك التحقق مما إذا كان ذلك الكائن يمشي مشي البطة، وصوته كصوت البطة، بدلًا من أن تسأل عما إذا كان الكائن بطةً.
عندما تحتوي عدة أصناف أو أصناف فرعية على توابع لها نفس الأسماء، ولكن بسلوكيات مختلفة، نقول إنّ تلك الأصناف متعددة الأشكال (polymorphic) لأنها تستعمل واجهة موحدة يمكن استخدامها مع كيانات من أنواع مختلفة. يمكن للدوال تقييم ومعالجة هذه التوابع متعدِّدة الأشكال دون معرفة أصنافها.
إنشاء أصناف متعددة الأشكال
للاستفادة من التَعدُّدية الشكلية، سننشئ صنفين مختلفين لاستخدامهما مع كائنين مختلفين. يحتاج هذان الصنفان المختلفان واجهة موحدة يمكن استخدامها بطريقة تعدُّدية الشكل (polymorphically)، لذلك سنعرّف فيهما توابع مختلفة، ولكن لها نفس الاسم.
سننشئ صنفًا باسم Shark
وصنفُا آخر باسم Clownfish
، وسيُعرِّف كل منهما التوابع swim()
و swim_backwards()
و skeleton()
.
class Shark(): def swim(self): print("القرش يسبح.") def swim_backwards(self): print("لا يمكن للقرش أن يسبح إلى الوراء، لكن يمكنه أن يغوص إلى الوراء.") def skeleton(self): print("هيكل القرش مصنوع من الغضروف.") class Clownfish(): def swim(self): print("سمكة المهرج تسبح.") def swim_backwards(self): print("يمكن لسمكة المهرج أن تسبح إلى الخلف.") def skeleton(self): print("هيكل سمكة المهرج مصنوع من العظام.")
في الشيفرة أعلاه، لدى الصنفين Shark
و Clownfish
ثلاث توابع تحمل نفس الاسم بيْد أنّ وظائف تلك التوابع تختلف من صنف لآخر.
دعنا نستنسخ (instantiate) من هذين الصنفين كائنين:
... sammy = Shark() sammy.skeleton() casey = Clownfish() casey.skeleton()
عند تنفيذ البرنامج باستخدام الأمر python polymorphic_fish.py
، يمكننا أن نرى أنّ كل كائن يتصرف كما هو متوقع:
هيكل القرش مصنوع من الغضروف. هيكل سمكة المهرج مصنوع من العظام.
الآن وقد أصبح لدينا كائنان يستخدمان نفس الواجهة، فبمقدورنا استخدام هذين الكائنين بنفس الطريقة بغض النظر عن نوعيهما.
التعددية الشكلية في توابع الأصناف
لإظهار كيف يمكن لبايثون استخدام الصنفين المختلفين اللذين عرّفناهما أعلاه بنفس الطريقة، سننشئ أولاً حلقة for، والتي ستمر على صف من الكائنات. ثم سنستدعي التوابع بغض النظر عن نوع الصنف الذي ينتمي إليه كل كائن. إلا أننا سنفترض أنّ تلك التوابع موجودة في كل تلك الأصناف.
... sammy = Shark() casey = Clownfish() for fish in (sammy, casey): fish.swim() fish.swim_backwards() fish.skeleton()
لدينا كائنان، sammy
من الصنف Shark
، و casey
من الصنف Clownfish
. تمر حلقة for
على هذين الكائنين، وتستدعي التوابع swim()
و swim_backwards()
و skeleton()
على كل منها.
عند تنفيذ البرنامج، سنحصل على المخرجات التالية:
القرش يسبح. لا يمكن للقرش أن يسبح إلى الوراء، لكن يمكنه أن يغوص إلى الوراء. هيكل القرش مصنوع من الغضروف. سمكة المهرج تسبح. يمكن لسمكة المهرج أن تسبح إلى الخلف. هيكل سمكة المهرج مصنوع من العظام.
مرت الحلقة for
على الكائن sammy
من الصنف Shark
، ثم على الكائن casey
المنتمي إلى الصنف Clownfish
، لذلك نرى التوابع الخاصة بالصنف Shark
قبل التوابع الخاصة بالصنف Clownfish
.
يدلُّ هذا على أنَّ بايثون تستخدم هذه التوابع دون أن تعرف أو تعبأ بتحديد نوع الصنف الخاص بالكائنات. وهذا مثال حي على استخدام التوابع بطريقة مُتعدِّدَة الأشكال.
التعددية الشكلية في الدوال
يمكننا أيضًا إنشاء دالة تقبل أيّ شيء، وهذا سيسمح باستخدام التعددية الشكلية.
لننشئ دالة تسمى in_the_pacific()
، والتي تأخذ كائنًا يمكننا تسميته fish
. رغم أننا سنستخدم الاسم fish
، إلا أنه يمكننا استدعاء أي كائن في هذه الدالة:
… def in_the_pacific(fish):
بعد ذلك، سنجعل الدالة تستخدم الكائن fish
الذي مرّرناه إليها. وفي هذه الحالة، سنستدعي التابع swim()
المعرّف في كل من الصنفين Shark
و Clownfish
:
... def in_the_pacific(fish): fish.swim()
بعد ذلك، سننشئ نسخًا (instantiations) من الصنفين Shark
و Clownfish
لنمرّرهما بعد ذلك إلى نفس الدالة in_the_pacific()
:
... def in_the_pacific(fish): fish.swim() sammy = Shark() casey = Clownfish() in_the_pacific(sammy) in_the_pacific(casey)
عند تنفيذ البرنامج، سنحصل على المخرجات التالية:
القرش يسبح. سمكة المهرج تسبح.
رغم أننا مرّرنا كائنًا عشوائيًا (fish
) إلى الدالة in_the_pacific()
عند تعريفها، إلا أننا ما زلنا قادرين على استخدامها استخدامًا فعالًا، وتمرير نسخ من الصنفين Shark
و Clownfish
إليها. استدعى الكائنُ casey
التابعَ swim()
المُعرَّف في الصنف Clownfish
، فيما استدعى الكائنُ sammy
التابعَ swim()
المُعرَّف في الصنف Shark
.
خلاصة
تسمح التعدُّدية الشكلية باستخدام الكائنات بغض النظر عن نوعها، وهذا يوفر لبايثون مرونة كبيرة، وقابلية لتوسيع الشيفرة الكائنية.
هذه المقالة جزء من سلسة مقالات حول تعلم البرمجة في بايثون 3.
ترجمة -وبتصرّف- للمقال How To Apply Polymorphism to Classes in Python 3 لصاحبته Lisa Tagliaferri
اقرأ أيضًا
- المقالة التالية: كيف تستخدم منقح بايثون
- المقالة السابقة: وراثة الأصناف في بايثون 3
- المرجع الشامل إلى تعلم لغة بايثون
- كتاب البرمجة بلغة بايثون
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.