بايثون لغةٌ برمجة كائنية (object-oriented programming language). تركز البرمجة الكائنية (OOP) على كتابة شيفرات قابلة لإعادة الاستخدام، على عكس البرمجة الإجرائية (procedural programming) التي تركز على كتابة تعليمات صريحة ومتسلسلة.
تتيح البرمجة الكائنية لمبرمجي بايثون كتابة شيفرات سهلة القراءة والصيانة، وهذا مفيد للغاية عند تطوير البرامج المُعقَّدة.
التمييز بين الأصناف والكائنات أحدُ المفاهيم الأساسية في البرمجة الكائنية، ويوضح التعريفان التاليان الفرق بين المفهومين:
- الصنف - نموذج عام تُنسج على منواله كائنات يُنشِئها المبرمج. يُعرِّف الصنف مجموعةً من الخاصيات التي تميز أي كائن يُستنسَخ (instantiated) منه.
- الكائن - نسخةٌ (instance) من الصنف، فهو تجسيد عملي للصنف داخل البرنامج.
تُستخدَم الأصناف لإنشاء أنماط، ثم تُستعمَل تلك الأنماط لإنشاء كائنات منها.
ستتعلم في هذا الدرس كيفيَّة إنشاء الأصناف والكائنات، وتهيئة الخاصيات باستخدام تابعٍ بانٍ (constructor method)، والعمل على أكثر من كائن من نفس الصنف.
الأصناف
الأصناف هي نماذج عامة تُستخدم لإنشاء كائنات وسبق أن عرَّفناها آنفًا.
تُنشَأ الأصناف باستخدام الكلمة المفتاحية class
، بشكل مشابه [لتعريف الدوال](رابط المقالة 34) الذي يكون باستخدام الكلمة المفتاحية def
.
دعنا نعرّف صنفًا يسمى Shark
، ونجعل له تابعين مرتبطين به، swim
و be_awesome
:
class Shark: def swim(self): print("The shark is swimming.") def be_awesome(self): print("The shark is being awesome.")
تُسمَّى مثل هذه الدوال «توابعًا» (methods) لأنهما معرفتان داخل الصنف Shark
؛ أي أنهما دالتان تابعتان للصنف Shark
.
الوسيط الأول لهاتَين الدالتين هو self
، وهو مرجع إلى الكائنات التي يتم بناؤها من هذا الصنف. للإشارة إلى نُسخ (أو كائنات) من الصنف، يوضع self
دائمًا في البداية، لكن يمكن أن تكون معه وسائط أخرى.
لا يؤدي تعريف الصنف Shark
إلى إنشاء كائنات منه، وإنما يعرّف فقط النمط العام لتلك الكائنات، والتي يمكننا تعريفها لاحقًا. لذا، إذا نفّذت البرنامج أعلاه الآن، فلن يُعاد أي شيء.
الكائنات
الكائن هو نسخةٌ (instance) من صنف. ويمكن أن نأخذ الصنف Shark
المُعرَّف أعلاه، ونستخدمه لإنشاء كائن يعدُّ نسخةً منه.
سننشئ كائنًا Shark
يسمى sammy
:
sammy = Shark()
لقد أحلنا على الكائن sammy
ناتج الباني Shark()
، والذي يعيد نسخةً من الصنف.
سنستخدم في الشيفرة التالية التابعين الخاصين بالكائن sammy
:
sammy = Shark() sammy.swim() sammy.be_awesome()
يستخدم الكائن sammy
التابعين swim()
و be_awesome()
، وقد استدعينَاهما باستعمال المعامل النقطي (.
)، والذي يُستخدم للإشارة إلى خاصيات أو توابع الكائنات. في هذه الحالة، استدعينا تابعًا، لذلك استعملنا قوسين مثلما نفعل عند استدعاء دالة.
الكلمة self
هي معامل يُمرّر إلى توابع الصنف Shark
، في المثال أعلاه، يمثّل self
الكائن sammy
. يتيح المعامل self
للتوابع الوصول إلى خاصيات الكائن الذي استُدعيت معه.
لاحظ أننا لم نمرر شيئًا داخل القوسين عند استدعاء التابع أعلاه، ذلك أنّ الكائن sammy
يُمرّر تلقائيًا مع العامل النقطي.
البرنامج التالي يوضح لنا الأمر:
class Shark: def swim(self): print("The shark is swimming.") def be_awesome(self): print("The shark is being awesome.") def main(): sammy = Shark() sammy.swim() sammy.be_awesome() if __name__ == "__main__": main()
لننفذ البرنامج لنرى ما سيحدث:
python shark.py
ستُطبع المخرجات التالية:
The shark is swimming. The shark is being awesome.
في الشيفرة أعلاه، استدعى الكائن sammy
التابعين swim()
و be_awesome()
في الدالة الرئيسية main()
.
الباني
يٌستخدم الباني (Constructor Method) لتهيئة البيانات الأولية، ويُنفَّذ لحظة إنشاء الكائن. في تعريف الصنف، يأخذ الباني الاسم __init__
، وهو أول تابع يُعرّف في الصنف، ويبدو كما يلي:
class Shark: def __init__(self): print("This is the constructor method.")
إذا أضفت التابع __init__
إلى الصنف Shark
في البرنامج أعلاه، فسيَطبع البرنامجُ المخرجات التالية:
This is the constructor method. The shark is swimming. The shark is being awesome.
يُنفَّذ الباني تلقائيًا، لذا يستخدمه مطورو بايثون لتهيئة أصنافهم.
سنُعدِّل الباني أعلاه، ونجعله يستخدم متغيرًا اسمه name
سيمثّل اسم الكائن. في الشيفرة التالية، سيكون المتغير name
المعامل المُمرَّر إلى الباني، ونحيل قيمته إلى الخاصية self.name
:
class Shark: def __init__(self, name): self.name = name
بعد ذلك، يمكننا تعديل السلاسل النصية في دوالنا للإشارة إلى اسم الصنف، على النحو التالي:
class Shark: def __init__(self, name): self.name = name def swim(self): # الإشارة إلى الاسم print(self.name + " is swimming.") def be_awesome(self): # الإشارة إلى الاسم print(self.name + " is being awesome.")
أخيرًا، يمكننا تعيين اسم الكائن sammy
عند القيمة "Sammy"
(أي قيمة الخاصية name
) بتمريره إلى Shark()
عند إنشائه:
class Shark: def __init__(self, name): self.name = name def swim(self): print(self.name + " is swimming.") def be_awesome(self): print(self.name + " is being awesome.") def main(): # Shark تعيين اسم كائن sammy = Shark("Sammy") sammy.swim() sammy.be_awesome() if __name__ == "__main__": main()
عرّفنا التابع __init__
، والذي يقبل مُعاملين self
و name
(تذكر أن المعامل self
يُمرر تلقائيا إلى التابع)، ثم عرّفنا متغيرًا فيه.
عند تنفيذ البرنامج:
python shark.py
سنحصل على:
Sammy is swimming. Sammy is being awesome.
لقد طُبع الاسم الذي مرّرناه إلى الكائن. ونظرًا لأنّ الباني يُنفّذ تلقائيًا، فلست بحاجة إلى استدعائه بشكل صريح، فيكفي تمرير الوسائط بين القوسين التاليين لاسم الصنف عند إنشاء نسخة جديدة منه.
إذا أردت إضافة معامل آخر، مثل age
، فيمكن ذلك عبر تمريره إلى التابع __init__
:
class Shark: def __init__(self, name, age): self.name = name self.age = age
عند إنشاء الكائن sammy
، سنمرر عُمره أيضًا بالإضافة إلى اسمه:
sammy = Shark("Sammy", 5)
إذًا، تتيح البانيات تهيئة خاصيات الكائن لحظة إنشائه.
العمل مع عدة كائنات
تتيح لنا الأصناف إنشاء العديد من الكائنات المتماثلة التي تتبع نفس النمط. لتفهم ذلك بشكل أفضل، دعنا نضيف كائنًا آخر من الصنف Shark
إلى برنامجنا:
class Shark: def __init__(self, name): self.name = name def swim(self): print(self.name + " is swimming.") def be_awesome(self): print(self.name + " is being awesome.") def main(): sammy = Shark("Sammy") sammy.be_awesome() stevie = Shark("Stevie") stevie.swim() if __name__ == "__main__": main()
لقد أنشأنا كائنًا ثانيًا من الصنف Shark
يسمى stevie
، ومرّرنا إليه الاسم "Stevie"
. في هذا المثال، استدعينا التابع be_awesome()
مع الكائن sammy
، والتابع swim()
مع الكائن stevie
.
لننفذ البرنامج:
python shark.py
سنحصل على المخرجات التالية:
Sammy is being awesome. Stevie is swimming.
يبدو ظاهرًا في المخرجات أننا نستخدم كائنين مختلفين، الكائن sammy
والكائن stevie
، وكلاهما من الصنف Shark
.
تتيح لنا الأصناف إنشاء عدة كائنات تتبع كلها نفس النمط دون الحاجة إلى بناء كل واحد منها من البداية.
خلاصة
تطرَّقنا في هذا الدرس إلى عِدَّة مفاهيم، مثل إنشاء الأصناف، وإنشاء الكائنات، وتهيئة الخاصيات باستخدام البانيات، والعمل مع أكثر من كائن من نفس الصنف.
تُعدُّ البرمجة الكائنية أحد المفاهيم الضرورية التي ينبغي أن يتعلمها كل مبرمجي بايثون، لأنها تساعد على كتابة شيفرات قابلة لإعادة الاستخدام، إذ أنَّ الكائنات التي تُنشَأ في برنامج ما يمكن استخدامها في برامج أخرى. كما أنّ البرامج الكائنية عادة ما تكون أوضح وأكثر مقروئية، خصوصًا في البرامج المعقدة التي تتطلب تخطيطًا دقيقًا، وهذا بدوره يسهل صيانة البرامج مستقبلًا.
هذه المقالة جزء من سلسة مقالات حول تعلم البرمجة في بايثون 3.
ترجمة -وبتصرّف- للمقال How To Construct Classes and Define Objects in Python 3 لصاحبته Lisa Tagliaferri
اقرأ أيضًا
- المقالة التالية: فهم متغيرات الأصناف والنسخ في بايثون 3
- المقالة السابقة: كيفية استخدام args و *kwargs في بايثون 3
- المرجع الشامل إلى تعلم لغة بايثون
- كتاب البرمجة بلغة بايثون
أفضل التعليقات
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.