Header Ads

بايثون كائنية التوجه



تتميز لغة البرمجة بايثون باللغة غرضية التوجه منذ البدايات ولذلك فإن إنشاء الصفوف والأغراض تعتير عملية سهلة وفي هذا القسم سيتعلم المستخدم كيفية استخدام الدعم الذي تقدمه لغة البرمجة بايثون غرضية التوحه.
التالي هو مقدمة للبرمجة غرضية التوجه.


مراجعة لمصطلحات البرمجة غرضية التوجه

  • الصف: هو نموذج يتم تعريفه من قبل المستخدم لغرض ما والذي يعرف مجموعة من السمات التي تصف أي غرض من الصف وهذه السمات يمكن ان تكون بيانات وطرق.
  • متحول الصف: وهو المتحول الذي تتم مشاركته من كافة المساحات ضمن الصف ويتم تعريف هذا المتحول ضمن الصف لكن خارج طرق الصف.
  • عضو البيانات: متحول الصف أو متحول المسافة التي تضبط البيانات المجتمعة مع الصف وأغراضها.
  • تابع التحميل الزائد: إسناد أكثر من مفهوم أو مهمة للتابع الخاص وتختلف هذه العملية المنجزة باختلاف نماذج الأغراض أو المدخلات المتضمنة.
  • متحول المسافة: المتحول الذي يتم تعريفه ضمن الطريقة ويعود حصراً لمسافة الصف الحالية.
  • الوراثة: وتعني نقل المميزات من صف إلى صف آخر مشتق منه.
  • المسافة: الأغراض المستقلة لصف محدد.
  • المثيل: تحديد مسافة الصف.
  • الطريقة: تعرف خاص للتابع المعرف في تعريف الصف.
  • الغرض: مسافة مميزة من تركيبة البيانات والمعرفة ضمن صفها.
  • مشغل التحميل الزائد: إسناد أكثر من تابع إلى مشغل خاص.

إنشاء الصفوف


تستخدم التعليمة class لإنشاء صفوف جديدة وتعريفها ويتم وضع اسم الصف كالتالي:
class ClassName:

'Optional class documentation string'

class_suite

  • للصف سلسلة وثائق والتي يمكن الوصول إليها عن طريق __doc__ .
  • تتألف الـ class_suite من كافة التعليمات المعرفة كأعضاء للصف وسمات البيانات والتوابع.

مثال



class Employee:
 'Common base class for all employees'
 empCount = 0

 def __init__(self, name, salary):
 self.name = name
 self.salary = salary
 Employee.empCount += 1
 
 def displayCount(self):
 print "Total Employee %d" % Employee.empCount

 def displayEmployee(self):
 print "Name : ", self.name, ", Salary: ", self.salary

إنشاء أغراض المسافة


لإنشاء مسافة ما ضمن الصف يجب استدعاء الصف باستخدام اسم الصف وإسناد المدخلات.
"This would create first object of Employee class"
emp1 = Employee("Zara", 2000)
"This would create second object of Employee class"
emp2 = Employee("Manni", 5000)

الوصول إلى السمات


يتم الوصول إلى سمات الأغراض باستخدام المشغل dot مع الغرض ويتم الوصول إلى متحول الصف باستخدام اسم الصف كالتالي –
emp1.displayEmployee()
emp2.displayEmployee()
print "Total Employee %d" % Employee.empCount

والآن عند وضع كافة المفاهيم سوية:
#!/usr/bin/python

class Employee:
   'Common base class for all employees'
   empCount = 0

   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1
   
   def displayCount(self):
     print "Total Employee %d" % Employee.empCount

   def displayEmployee(self):
      print "Name : ", self.name,  ", Salary: ", self.salary

"This would create first object of Employee class"
emp1 = Employee("Zara", 2000)
"This would create second object of Employee class"
emp2 = Employee("Manni", 5000)
emp1.displayEmployee()
emp2.displayEmployee()
print "Total Employee %d" % Employee.empCount

فتظهر النتيجة التالية:
Name: Zara,Salary: 2000
Name: Manni,Salary: 5000
Total Employee 2

ويمكن إضافة سمة الجمع والإزالة والتعديل للصف والأغراض –
emp1.age = 7  # Add an 'age' attribute.
emp1.age = 8  # Modify 'age' attribute.
del emp1.age  # Delete 'age' attribute.

يمكن استخدام التوابع التالية بدلاً من استخدام التعليمات الاعتيادية :
  • التابع getattr(obj, name[, default]) : للوصول إلى سمة الغرض.
  • التابع hasattr(obj,name) :لاختبار فيما إذا كانت السمة موجودة أم لا.
  • التابع setattr(obj,name,value)لضبط السمة إذا كانت غير موجود وبعدها يتم إنشاؤها.
  • التابعdelattr(obj, name) : لحذف السمة.

hasattr(emp1, 'age')    # Returns true if 'age' attribute exists
getattr(emp1, 'age')    # Returns value of 'age' attribute
setattr(emp1, 'age', 8) # Set attribute 'age' at 8
delattr(empl, 'age')    # Delete attribute 'age'

سمات الصفوف المبنية


جميع السبات في بايثون لها السمات التالية ويمكن الوصول إليها باستخدام المشغل dot مثل أي سمة أخرى-
  • __dict__ : القاموس الحاوي على الفراغات الاسمية للصف.
  • __doc__ : سلسلة الصف أو لاشيئ إذا كانت غير معرفة.
  • __name__ : اسم الصف.
  • __module__ : اسم الوحدة التي تم تعريف الصف عندها وهذه السمة تقابل السمة "__main__" في النمط التفاعلي.
  • __bases__ : الصف الفارغ المحتمل والحاوي على الصف الأساسية وفق تراتبية حدوثها في قائمة الصف الأساسية.

ومن أجل الصف السابق يمكن استخدام كافة السمات –
#!/usr/bin/python

class Employee:
   'Common base class for all employees'
   empCount = 0

   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1
   
   def displayCount(self):
     print "Total Employee %d" % Employee.empCount

   def displayEmployee(self):
      print "Name : ", self.name,  ", Salary: ", self.salary

print "Employee.__doc__:", Employee.__doc__
print "Employee.__name__:", Employee.__name__
print "Employee.__module__:", Employee.__module__
print "Employee.__bases__:", Employee.__bases__
print "Employee.__dict__:", Employee.__dict__



فتظهر النتيجة التالية


Employee.__doc__: Common base class for all employees
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: ()
Employee.__dict__: {'__module__': '__main__', 'displayCount':
<function displayCount at 0xb7c84994>, 'empCount': 2, 
'displayEmployee': <function displayEmployee at 0xb7c8441c>, 
'__doc__': 'Common base class for all employees', 
'__init__': <function __init__ at 0xb7c846bc>}

تدمير الكائنات


تقوم لغة البرمجة بايثون بحذف الأغراض التي لاحاجة لها بشكل تلقائي وذلك لتوفير مساحة ضمن الذاكرة وتسمى هذه العملية بجمع النفايات حيث يبدأ جامع النفايات خلال عملية تنفيذ البرنامج ويتوقف عندما يصل العداد المرجعي للغرض المنفذ إلى الصفر.
يزداد هذا العداد عندما عندما يسند له اسم جديد او عند وضعه في مكان جديد مثل (قائمة أو صف أو قاموس). ويتناقص عندما يتم حذفه باستخدام التعليمة del ويعاد إسناد المرجع للعداد أو يخرج خارج التنفيذ وعندما يصل للصفر فإن بايثون تقوم بجمعه تلقائياً.
a = 40      # Create object <40>
b = a       # Increase ref. count  of <40> 
c = [b]     # Increase ref. count  of <40> 

del a       # Decrease ref. count  of <40>
b = 100     # Decrease ref. count  of <40> 
c[0] = -1   # Decrease ref. count  of <40> 


تقوم هذه الأداة __del__() بطباعة اسم الصف للمسافة التي هي على وشك الإزالة-

#!/usr/bin/python


class Point:
def __init( self, x=0, y=0):
self.x = x
self.y = y
def __del__(self):
class_name = self.__class__.__name__
print class_name, "destroyed"

pt1 = Point()
pt2 = pt1
pt3 = pt1print id(pt1), id(pt2), id(pt3) # prints the ids of the obejcts
del pt1del pt2del pt3


فتظهر النتيجة التالية


308340132430834013243083401324
Point destroyed

توريث الصف


بدلاً من إنشاء صف جديد فإنه من الممكن اشتقاق صف من صف آخر موجود مسبقاً وذلك بوضع الصف الجديد بين قوسين بعد اسم الصف الجديد.
يتم توريث كافة سمات الصف الأصلي للصف الوليد ويمكن استخدام هذه السمات مع الصف الجديد كما لو أنها أنشئت ضمنه وكذلك الأمر بالنسبة للطرق والبيانات.


الشيفرة البرمجية


class SubClassName (ParentClass1[, ParentClass2, ...]):
   'Optional class documentation string'
   class_suite

مثال



#!/usr/bin/python

class Parent:        # define parent class
   parentAttr = 100
   def __init__(self):
      print "Calling parent constructor"

   def parentMethod(self):
      print 'Calling parent method'

   def setAttr(self, attr):
      Parent.parentAttr = attr

   def getAttr(self):
      print "Parent attribute :", Parent.parentAttr

class Child(Parent): # define child class
   def __init__(self):
      print "Calling child constructor"

   def childMethod(self):
      print 'Calling child method'

c = Child()          # instance of child
c.childMethod()      # child calls its method
c.parentMethod()     # calls parent's method
c.setAttr(200)       # again call parent's method
c.getAttr()          # again call parent's method

فتظهر النتيجة التالية

Calling child constructor
Calling child method
Calling parent method
Parent attribute : 200

وبشكل مشابه يمكن اشتقاق صف من صفوف متعددة كالتالي-
class A:        # define your class A
.....

class B:         # define your calss B
.....

class C(A, B):   # subclass of A and B
.....

يمكن استخدام التابع issubclass() أو التابع isinstance() لتفحص العلاقات بين صفين أو مسافتين.
  • التابع issubclass(sub, sup)يعيد القيمة صح إذا كان الصف الفرعي المعطىsub فعلاً صفاً فرعياً للصف sup .
  • التابع isinstance(obj, Class)يعيد القيمة صح إذا كان obj مسافة للصف أوClassأو مسافة للصف الفرعي للصف.

تجاهل الطرق


يمكن زيادة التحميل بالنسبة لطرق الصفوف لعدة أسباب أهمها الحاجة لوجود توابع خاصة أو مختلفة في الصف الفرعي.

مثال
#!/usr/bin/python

class Parent:        # define parent class
   def myMethod(self):
      print 'Calling parent method'

class Child(Parent): # define child class
   def myMethod(self):
      print 'Calling child method'

c = Child()          # instance of child
c.myMethod()         # child calls overridden method

فتظهر النتيجة التالية
Calling child method


تجاهل المشغلات


لنفترض إنشاء صف Vector لتمثيل شعاعين ثنائيي البعد. ماذا سيحدث لو حاول المشغل إضافة الجمع إليهما؟!
يمكن للمستخدم تعريف الطريقة __add__في الصف لإنجاز عملية جمعوبعدها يسلك المشغل الخاص بالجمع سلوكاً مسبق التوقع.

مثال
#!/usr/bin/python

class Vector:
   def __init__(self, a, b):
      self.a = a
      self.b = b

   def __str__(self):
      return 'Vector (%d, %d)' % (self.a, self.b)
   
   def __add__(self,other):
      return Vector(self.a + other.a, self.b + other.b)

v1 = Vector(2,10)
v2 = Vector(5,-2)
print v1 + v2

فتظهر النتيجة التالية
Vector(7,8)

تخبئة البيانات


يمكن أن تكون سمات الغرض ظاهرة أو غير ظاهرة خارج تعريف الصف ولجعل هذه السمات غير ظاهرة خارج تعريف الصف يتم تسميتها بوضع خطين سفليين قبلها ( __ ).

مثال
#!/usr/bin/python

class JustCounter:
   __secretCount = 0
  
   def count(self):
      self.__secretCount += 1
      print self.__secretCount

counter = JustCounter()
counter.count()
counter.count()
print counter.__secretCount



فتظهر النتيجة التالية
1
2
Traceback (most recent call last):
  File "test.py", line 12, in <module>
    print counter.__secretCountAttributeError: JustCounter instance has no attribute '__secretCount'



تقوم لغة البرمجة بايثون بحماية هذه الأعضاء من خلال التغيير الداخلي للاسم ليتضمن اسم الصف. ويمكن الوصول إلى هذه السمات مثل object._className__attrName .من الممكن استبدال السطر الأخير كالتالي :
.........................
print counter._JustCounter__secretCount



فتظهر النتيجة التالية
1
2
2

يتم التشغيل بواسطة Blogger.