• 0
Mr.B

البرمجة الكائنية OOP لمبرمج Python الحديث

سؤال

السلام عليكم ورحمة الله وبركاته

البرمجة الكائنية دائماً ماتكون عقدة لدى المُبرمج الحديث. فأغلب كُتب البرمجة تعتقد أن المبرمج قادم من جافا أو من 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 / y

self يجب أن تُمرر في كل الوظائف داخل أي 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__ مباشرة وتنفيذ مابداخلها :

$ python

Python 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.py

2.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)

كائني.

في حال كان هناك غُموض فرجاءً طلب التوضيح كي أصححه.

بالتوفيق

تم تعديل بواسطه Mr.B
3

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

6 إجابة على هذا السؤال .

  • 0

اشكرك على الشرح الجميل لكن سؤال

--------------

هل الكلاس ضروري في تطبيقات الويب في بايثون ام لا

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

السلام عليكم

جهد مشكور بلاشك ولكنك تحتاج لتحديد أدق لمفهوم الصف والكائن فأنت تتعامل مع الصف كأنه "مكتبة" والأمر ليس كذلك

فأنت تستطيع مثلا إنشاء مكتبة إسمها MyMath وتعرف داخلها دوال add, sub, mul, div وتستطيع الوصوف إليها MyMath.add و MyMath.sub وهكذا

أنصحك تراجع

http://programming-fr34ks.net/wiki/index.php/PythonGuide/OOP_Basics

http://programming-fr34ks.net/wiki/index.php/PythonGuide/OOP_Inheritance

تحياتي

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

جزاك الله خيرا

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

اهلا اخي بركات اشتقنا لك ..

 

موضوع جميل وشرح رائع

 

ارجو ان تذهب لمجتمع لينكس العربي ﻻني ارسلت هناك لك رسالة

 

احترامي ..

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

شكرا MR.B على هذا المجهود الكبير وجزاك الله خير :)

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

لا اقول الا حرف وكلمة 

الى المفضلة 

شكرا جدا واتمنا ان تجيب على تسائلات الاعضاء وتحاول ان تستمر 

انا احب الشرح الكتابي اكثر من الشرح الفيديو 

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

من فضلك سجل دخول لتتمكن من التعليق

ستتمكن من اضافه تعليقات بعد التسجيل



سجل دخولك الان

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .