السلام عليكم ورحمة الله وبركاته
البرمجة الكائنية دائماً ماتكون عقدة لدى المُبرمج الحديث. فأغلب كُتب البرمجة تعتقد أن المبرمج قادم من جافا أو من C++ أو تبالغ في تصوير البرمجة الكائنية وتجعلها شيء مختلف جداً أو تستخدم تشبيهات خطائة في الشرح.
الذي يحصل أنّ المبرمج الحديث يقع في حيرة من أمره عندما ﻻيستطيع تمميز "هذا الشيء الجديد والسحري".
في الواقع أنّها أبسط مما نعتقد إذا تجنبا التعمق في فلسفتها والمصطلحات والكلام الرنان. ومتأكّد بأنه ﻻبد أنه تعامل معها وهو ﻻيعلم.
قبل البدء
ماذا تحتاج قبل البدء :
* أن تعرف أساسيات بايثون.
* أن تعرف ماهي الدوال def وكيف تستخدمها.
* أن تكون مرن في تفكيرك وتُجرّب بنفسك. إلى أن تشتغل اللمبة.
طريقة الشرح
ستكون طريقة عمليّة على أمثلة تجربها بنفسك لأن الكلام النظري ﻻيفيد هنا. وسنقوم بكتابة مكتبة بسيطة جداً جداً للرياضيات. أكره الرياضات وكثير مثلي لذا مكتبتنا لن تحتوي على شيء سوى الجمع + والطرح - والضرب × والقسمة ÷. أشياء نعرفها منذ الطفولة.
إنشاء Class
مثلاً تريد كتابة مكتبة للرياضيات تقوم بالعمليات الأساسية +,-,×,÷ يمكنك عمل class إسمه MyMath مثلاً :
#!/usr/bin/python
# -*- coding: utf-8 -*-
class MyMath:
passأو :
#!/usr/bin/python
# -*- coding: utf-8 -*-
class MyMath(object):
passهذا أبسط class يُمكن كتابتة. الآن جميع مايتعلّق بمكتبتنا سيكون داخل MyMath.
كتابة وظائف
تريد أن تكتب الوظائف (الدوال) الاساسية +,-,×,÷. أيّ دالة داخل class تُسمّى وظيفة وليست دالة (هي نفس الشيء فعلياً ولكنها فقط فلسفة جديدة وأسماء جديدة):
#!/usr/bin/python
# -*- coding: utf-8 -*-
class MyMath(object):
def add(self, x, y):
return x + y
def sub(self, x, y):
return x - y
def mul(self, x, y):
return x * y
def div(self, x, y):
return x / yself يجب أن تُمرر في كل الوظائف داخل أي class.
إنشاء كائن وإستخدام الـclass
نريد أن نستخدمها. هنا يأتي دور الكائنات. لنتعلم بإنشاء كائن وإستخدامه:
#!/usr/bin/python
# -*- coding: utf-8 -*-
class MyMath(object):
def add(self, x, y):
return x + y
def sub(self, x, y):
return x - y
def mul(self, x, y):
return x * y
def div(self, x, y):
return x / y
mymath = MyMath() # هنا إنشاء الكائن
# وهنا إستخدام الوظائف
print mymath.add(1, 2) # 1 + 2 = 3
print mymath.sub(5, 3) # 5 - 3 = 2
print mymath.mul(2, 5) # 2 * 5 = 10
print mymath.div(4, 2) # 4 / 2 = 2أنشأنا كائن إسمه mymath. أعتقد أنه سبق أنّ مرّ عليك نفس الشيء :
foo = Boo()
أنت فعلياً تنشيء كائن إسمه foo من الـclass الذي إسمه Boo كي تستخدم الوظائف التي يقدّمها. وُبمكنك أن تنشيء أكثر من كائن لنفس الـclass.
foo = Boo() koo = Boo()
والوظائف هي الدوال التي بداخل الـclass.
الوراثة
نريد أن ننشء مكتبة ثانية إسمها AdvMyMath ,مكتبة الرياضيات المتقدّمة $: ,تحتوي على نفس العمليات الأولى بالإضافة للأسس, بدل إعادة كتابة add, sub .. إلخ, هنا تأتي فائدة الوراثة حيث تفيد كثيراً في إختار الكتابة . لنجعل AdvMyMath ترث MyMath :
#!/usr/bin/python
# -*- coding: utf-8 -*-
class MyMath(object):
def add(self, x, y):
return x + y
def sub(self, x, y):
return x - y
def mul(self, x, y):
return x * y
def div(self, x, y):
return x / y
class AdvMyMath(MyMath): # < هنا الوراثة
def power(self, x, y):
return x ** y
mymath = MyMath()
print mymath.add(1, 2) # 1 + 2 = 3
print mymath.sub(5, 3) # 5 - 3 = 2
print mymath.mul(2, 5) # 2 * 5 = 10
print mymath.div(4, 2) # 4 / 2 = 2
mymath2 = AdvMyMath()
print mymath2.add(1, 2) # 1 + 2 = 3
print mymath2.sub(5, 3) # 5 - 3 = 2
print mymath2.mul(2, 5) # 2 * 5 = 10
print mymath2.div(4, 2) # 4 / 2 = 2
print mymath2.power(2, 2) # 2 ^ 2 = 4 <-- NEW!!ﻻحظ كيف أن جميع الوظائف التي في MyMath إنتقلت إلى AdvMyMath بفضل هذا السطر:
class AdvMyMath(MyMath): # < هنا الوراثة
وأضفنا وظيفة جديدة إسمها power في AdvMyMath.
إعادة كتابة الوظائف
ﻻيُعجبنا تصرّف div في MyMath, إذا قسمنا رقمين مثل 1 على 2 تعطي 0 بدل 0.5, ونريد تصحيحها في AdvMyMath فقط, هنا تأتي فائدة إعادة كتابة الوظائف methods overriding :
#!/usr/bin/python
# -*- coding: utf-8 -*-
class MyMath(object):
def add(self, x, y):
return x + y
def sub(self, x, y):
return x - y
def mul(self, x, y):
return x * y
def div(self, x, y):
return x / y
class AdvMyMath(MyMath):
# Overriden
def div(self, x, y):
return float(x) / float(y)
def power(self, x, y):
return x ** y
mymath = MyMath()
print mymath.div(1, 2) # 1 / 2 = 0
mymath2 = AdvMyMath()
print mymath2.div(1, 2) # 1 / 2 = 0.5إستخدم البنّاء والصفات
نُريد أن نعدّل في تصرّف الـclass قليلاً بحيث نُدخل رقمين مرّة واحدة وتقوم الوظائف بتطبيق العمليات على تلك الأرقام دون الحاجة لإدخالها في كُل مرّة, هُنا يأتي دور البنّاء __init__ :
#!/usr/bin/python
# -*- coding: utf-8 -*-
class MyMath(object):
def __init__(self, num1, num2):
self.x = num1
self.y = num2
def add(self):
return self.x + self.y
def sub(self):
return self.x - self.y
def mul(self):
return self.x * self.y
def div(self):
return self.x / self.y
mymath = MyMath(2, 1) # ندخل الأرقام في المرّة الأولى فقط
print mymath.add() # 2 + 1 = 3
print mymath.sub() # 2 - 1 = 1
print mymath.mul() # 2 * 1 = 2
print mymath.div() # 2 / 1 = 2جرى تطبيق العمليّات على الأرقام 2 و 1 وأدخلناها مرّة واحده فقط عند إنشاء الكائن mymath.
* كما ترى فإن الأسماء تغيّرت قليلاً فالدوال أصبح إسمها وظائف, وأيضاً المتغيّرات التي تسبقها self تُسمّى الآن صفات.
* عند إنشاء كائن جديد, فسيقوم المُفسّر بإستدعاء دالة البنّاء __init__ مباشرة وتنفيذ مابداخلها :
$ pythonPython 2.6.6 (r266:84292, Dec 27 2010, 00:02:40) [GCC 4.4.5] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> >>> class MyClass(object): ... def __init__(self): ... print "You've called me! : )" ... >>> myclass = MyClass() You've called me! : ) >>>
توجد دالّة أخر وتسمّى الهدّام __del__ وهيّ الدالة التي تُستدعى إذا أنتهى الكائن كمايحدث إذا أغلق البرنامج أو حُذف الكائن يدوياً :
>>> >>> class MyClass(object):
... def __init__(self):
... print "You've called me! : )"
... def __del__(self):
... print "Byebye :("
...
>>> myclass = MyClass()
You've called me! : )
>>>
>>> myclass = 2
Byebye :(
>>>
>>> myclass = MyClass()
You've called me! : )
>>>
>>> del myclass
Byebye :(
>>>
>>> myclass = MyClass()
You've called me! : )
>>> exit()
Byebye :(
$
وتفيد في بعض الحالات كحالات التظيف مثل لو قٌمت class لمكتبة تتصل بخادم, يُمكنك أن تضع في الهدّام وظيفة لقطع الإتصال في الخادم إذا أغلق المُستخدم البرنامج دون قطع الإتصال.
* جميع تلك الوظائف موجودة سواءً كتبتها أو لم تكتبها. ولكنّها خاالية لاتحتوي شيء.
* في الذاكرة فإنّ self سيتمّ تغييرها إلى إسم الكائن. مثلاً إذا كان إسم الكائن mymath فستتحوّل كل self إلى عنوان mymath.
إنظر لهذا البرنامج :
#!/usr/bin/python
# -*- coding: utf-8 -*-
class MyClass():
def __init__(self):
x = 10
def pprint(self):
print x
myclass = MyClass()
myclass.pprint()لو حاولت تشغيه فسيعطي الخطأ :
$ python tot.py Traceback (most recent call last):
File "tot.py", line 21, in <module>
myclass.pprint()
File "tot.py", line 18, in pprint
print x
NameError: global name 'x' is not defined
$
يقول أنّ x غير مُعرفة , لأنّه ﻻيستطيع رؤيتها. الحلّ يكون في إستخدام self :
#!/usr/bin/python
# -*- coding: utf-8 -*-
class MyClass():
def __init__(self):
self.x = 10
def pprint(self):
print self.x
myclass = MyClass()
myclass.pprint()$ python tot.py 10 $
صفات محمية من التعديل
إذا أراد المُستخدم (المطوّر الذي يستخدم مكتبتك) تغيير هذه الأرقام يُمكنه أن يقوم بمثل هذا الشيء :
#!/usr/bin/python
# -*- coding: utf-8 -*-
class MyMath(object):
def __init__(self, num1, num2):
self.x = num1
self.y = num2
def add(self):
return self.x + self.y
def sub(self):
return self.x - self.y
def mul(self):
return self.x * self.y
def div(self):
return self.x / self.y
mymath = MyMath(2, 1)
print mymath.add() # 2 + 1 = 3
mymath.x = 4 # < !
mymath.y = 1 # < !
print mymath.add() # 4 + 1 = 5إذا لم تُرد المُستخدم أن يُعدّل عليها لسبب ما, فيمكنك أن تجعلها يُدخلها لمرّة واحدة وبعدها تُصبح للقراءة فقط وﻻيُسمح بالتعديل عليها وذلك بإضافة __ (شرطتين سُفلية) وستُصبح خاصّة
#!/usr/bin/python
# -*- coding: utf-8 -*-
class MyMath(object):
def __init__(self, num1, num2):
self.__x = num1
self.__y = num2
def add(self):
return self.__x + self.__y
def sub(self):
return self.__x - self.__y
def mul(self):
return self.__x * self.__y
def div(self):
return self.__x / self.__y
mymath = MyMath(2, 1)
print mymath.add() # 2 + 1 = 3
mymath.__x = 232
mymath.__y = 112
print mymath.add() # 2 + 1 = 3 ﻻشيء تغيّرالوظائف الخاصة
يُمكنك إستخدام __ مع الوظائف ايضاً وستصبح وظائف خاصة, مثلاً هناك وظيفة في الـclass ﻻعلاقة لها بوظيفة الـclass النهائية بل يحتاجها الـclass في عمله, مثل تحويل رقم إلى float :
#!/usr/bin/python
# -*- coding: utf-8 -*-
class MyMath(object):
def __init__(self, num1, num2):
self.__x = num1
self.__y = num2
def add(self):
return self.__x + self.__y
def sub(self):
return self.__x - self.__y
def mul(self):
return self.__x * self.__y
def div(self):
return self.__to_float(self.__x) / self.__to_float(self.__y)
# Private method
def __to_float(self, number):
return float(number)
mymath = MyMath(2, 1)
print mymath.div()قُمنا بعمل وظيفة خاصة بالـclass فقط إسمها __to_float تحول الأرقام إلى float. الآن لو حاول المُطوّر إستخدامها فلن يُسمح له :
#!/usr/bin/python
# -*- coding: utf-8 -*-
class MyMath(object):
def __init__(self, num1, num2):
self.__x = num1
self.__y = num2
def add(self):
return self.__x + self.__y
def sub(self):
return self.__x - self.__y
def mul(self):
return self.__x * self.__y
def div(self):
return self.__to_float(self.__x) / self.__to_float(self.__y)
def __to_float(self, number):
return float(number)
mymath = MyMath(2, 1)
print mymath.div()
# Error!
print mymath.__to_float(3)سيعطيه المُفسّر خطأ :
$ python tot.py2.0
Traceback (most recent call last):
File "tot.py", line 26, in <module>
print mymath.__to_float(3)
AttributeError: MyMath instance has no attribute '__to_float'
$
هذة أغلب وأهمّ مفاهيم البرمجة الكائنية التي ستتعامل معها كثيراً. فقط تذكّر هذه الأشياء :
الفلسفة الجديدة :
كما ذكرت أنّ الاسماء تغيّرت. لذا كي تذكرّ هذا الشيء,
class Boo(object):
def __init__(self):
self.x = 23
self.__y = "Hi"
def poo(self):
pass
def __roo(self):
pass
foo = Boo()
foo.poo()الـclass هو Boo
الوظيفة method هي poo
الوظيفة الخاصة private method هي __roo
الصفة attribute هي x
الصفة الخاصة private attribute هي __y
الكائن objectهو foo
الفرق النهائي بين برنامج تقليدي وبرنامج يستخدم البرمجة الكائنيّة :
#!/usr/bin/python
# -*- coding: utf-8 -*-
def MyMath_add(x, y):
return x + y
def MyMath_sub(x, y):
return x - y
def MyMath_mul(x, y):
return x * y
def MyMath_div(x, y):
return x / y
print MyMath_add(3, 2)تقليدي.
#!/usr/bin/python
# -*- coding: utf-8 -*-
class MyMath(object):
def add(self, x, y):
return x + y
def sub(self, x, y):
return x - y
def mul(self, x, y):
return x * y
def div(self, x, y):
return x / y
mymath = MyMath()
print mymath.add(3, 2)كائني.
في حال كان هناك غُموض فرجاءً طلب التوضيح كي أصححه.
بالتوفيق

