الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

مفهوم تغليف البيانات Data Encapsulation

بدأه ♥ حُوريّة ♥ في 12 يوليو 2009 · 8 رد · 5,484 مشاهدة · في لغة Python
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

post-140583-1247414310_thumb.gif

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

بســم الله الـرحمــن الرحيــم

,.,.,.,.,.

getter, setter

في لغة

Python 3

الهدف:

هو لمجرد التعرّف على كيفية بناء صنف class يحتوي على خصائص خاصة Private و على كيفية عمل خاصية التعيين setter و خاصية الجلب getter. و هذه المفاهيم تصب في مفهوم برمجي يتعلق بالبرمجة الكائنية OOP و تُسمى هندسياً بـ تغيلف البيانات Data Encapsulation أو بالأحرى و بخصوصية اكتر نستطيع أن نقول هذا الدرس هو حول إخفاء البيانات و التفاصيل data hiding.

الدرس مناسب جداً لمن لديهم خلفية مسبقة عن Python و عن هذه الآليات و المفاهيم من لغات و تجارب مع لغات أخرى. هذا يعني أنني متوقعة بعض الإلمام المسبق لهذه المفاهيم و خصوصاً هي مفاهيم بسيطة و ابتدائية و لكن نريد أن نتعرف عليها في لغة python و تحديداً النسخة التالتة. (زكية كتير هالـ python)...

ضيفتنا في هذا الدرس:

هي النقطة Point و هي عبارة عن صنف سنقوم بإنشائها تحتوي على ميزات النقطة المعروفة حسابية و هي القيم المحورية x و y. و هذه ليست إلا خصائص properties لأي نقطة ذات بعدين بالعالم.

الصنف Point:

حسناً نستطيع إنشاء هالصنف ببساطة كالتالي:

  1.  
  2. >>> class Point():
  3.  
  4. def __init__(self, x = 0, y = 0):
  5. self.x = x # خاصية المحور (إكس)
  6. self.y = y # خاصية المحور (واي)
  7.  

قمنا بتعيين قيم استهلالية للخاصية x,y بصفر لكل منهن. كما هو واضح في القيم الممررة إلى دالة الإنشاء __init__. و نستطيع من ثم بكل بساطة من تعيين هذه القيم لاحقاً أو قراءتهن كالتالي:

  1.  
  2. >>> p = Point() #إنشاء نقطة ببساطة
  3. >>> p.x
  4. 0
  5. >>> p.y
  6. 0
  7. >>> p.x = 10
  8. >>> p.x
  9. 10
  10. >>> # كزلك نفس الطريقة بالنسبة لـ واي
  11.  

و لكن هذه الطريقة ليست نموزجية برمجياً. لأن الخاصية x و y مكشوفة للمستخدم و يتستطيع عمل تعديلات عليهن و التصريف فيهن دون قيود او شروط... لذلك نقوم بإنشاء تلك الخصائص على أنها خاصة و لايمكن قراتهن او تعديلهن مباشرة و يتم زلك بواسطة إضافة شرطيتين سفلية double underscores (__) قبل اسم x و y.

و تكون الصنف Point كالتالي بعد لعملنا التعديل:

  1.  
  2. >>> class Point():
  3.  
  4. def __init__(self, x = 0, y = 0):
  5. self.__x = x #نلاحظ الشرطتين قبل الخاصية إكس
  6. self.__y = y # و هنا ايضاً قبل الخاصية واي
  7.  
  8.  

ولكن! الآن لا نستطيع ان نقوم بقراءة او تعيين هالخصائص كما فعلنا سابقاً و سينتج البرنامج اخطاء استسنائية لو حاولنا زلك:

  1.  
  2. >>> p = Point()
  3. >>> p.__x
  4. Traceback (most recent call last):
  5. File "<pyshell#42>", line 1, in <module>
  6. p.__x
  7. AttributeError: 'Point' object has no attribute '__x'
  8. >>> p.__y
  9. Traceback (most recent call last):
  10. File "<pyshell#43>", line 1, in <module>
  11. p.__y
  12. AttributeError: 'Point' object has no attribute '__y'
  13. >>>
  14.  

(كزابة هالـ python)

بتقول برسالة الأخطاء أنه لا يوجد خاصية __y أو __x!!! و الحقيقة هي خاصة private ...

خاصية التعيين و الجلب getter|setter:

الآن ما رأيكم لو قمنا بإنشاء خصائص بواسطتهن نقرأ و نكتب على تلك الخصائص و بنفس الوقت تكون خاصة private؟

هنا يأتي دور مفهوم setter و getter و هني عبارة عن دوال عادية تقوم بالوصول إلى تلك الخصائص x و y و تقرأهن و تكتب عليهن. ببساطة نعمل تعديل (إضافة) كالتالي:

  1.  
  2. >>> class Point():
  3.  
  4. def __init__(self, x = 0, y = 0):
  5. self.__x = x
  6. self.__y = y
  7.  
  8.  
  9. def getX(self): #دالة الجلب لقراءة إكس
  10. return self.__x
  11.  
  12. def getY(self): #دالة الجلب لقراءة واي
  13. return self.__y
  14.  
  15. def setX(self, x): # دالة التعيين لتعيين قيمة إكس
  16. # Typically we have to write a pre-condition here
  17. self.__x = x
  18.  
  19. def setY(self, y): # لتعيين قيمة واي
  20. # Typically we have to write a pre-condition here
  21. self.__y = y
  22.  
  23.  

و هنا نستعمل تلك الدوال بشكل طبيعي:

  1.  
  2. >>> p = Point()
  3. >>> p.getX() # نداء لدالة الجلب لقراءة إكس
  4. 0
  5. >>> p.setY(10) #نداء التعيين لتعيين قيمة اجديدة لـ واي
  6. >>> p.getY() # لقراءة قيمة واي الجديدة
  7. 10
  8. >>>
  9.  

الجميل بالموضوع الخاصية Decorator:

الآن ما رأيكم لو نتخلص من كلمة get و set و الأقواس و تعبئتهن داخل تلك الأقواس هكزا:

  1.  
  2. >>> p = Point()
  3. >>> p.x
  4. 0
  5. >>> p.y = 10
  6. >>> p.y
  7. 10
  8.  

حسناً هناك كلمات بسيطة نضيفهن قبل دوال الجلب و التعيين getters و setters تمكننا من كتابة الشيفرة السابقة بدون أي مشاكل و بنفس الوقت x و y في القسم الخاص private. و تكون الصنف Point بعد لعملنا التعديل و بشكلا النهائي كالتالي:

  1.  
  2. >>> class Point():
  3.  
  4. def __init__(self, x = 0, y = 0):
  5. self.__x = x
  6. self.__y = y
  7.  
  8. @property
  9. def x(self):
  10. return self.__x
  11. @property
  12. def y(self):
  13. return self.__y
  14. @x.setter
  15. def x(self, x):
  16. # Typically we have to write a pre-condition here
  17. self.__x = x
  18. @y.setter
  19. def y(self, y):
  20. # Typically we have to write a pre-condition here
  21. self.__y = y
  22.  

كل كلمة تبدأ بحرف (الآت) @ هي عبارة عن Decorator. نلاحظ ايضاً أن لخصائص الجلب getter نكتب الكلمة property. و لخصائص التعيين setter نكتب إسم الدالة و نقطة متبوعة بكلمة setter. و هنا python ستتعرف عليهن لاحقاً و ستهتم بباقي الأمر سواء تقرأ (تجلب) او تعيين بواسطة اسم الدالة مباشرة علامة = كما هو واضح بالتطبيق التالي:

  1.  

  2. >>> p = Point()
  3. >>> p.x
  4. 0
  5. >>> p.y
  6. 0
  7. >>> p.x = 10
  8. >>> p.x
  9. 10
  10. >>> p.y = 10
  11. >>> p.y
  12. 10
  13. >>>
  14.  

آسفة للإطالة...كنت عم بقص الوقت بالموضوع

معجبة اكتير بهالفكرة الزكية

موفقين يارب

bye

خيتكم رغــد

[وسط]

♥ Countess ♥

57899411.gif

♥

[/وسط]

#2

ملاحظة عامة: فلسفة بايثون لا تحبذ الاكثار من الـ getters و الـ setters, لا تستخدمها لمجرد استخدامها او لمجرد انك قادم من خلفية جافاوية (java),

#3

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

درس جميل أختنا رغد ... هل يطبق الدرس على ما قبل python 3؟

سبحانك اللهم و بحمدك ، أشهد أن لا إله إلا أنت ، أستغفرك ربي و أتوب إليك

مدونتي

http://www.facebook.com/brmjt

#4

جميل جدا :) أعشق هذا النوع من المواضيع.

مع تعقيب بسيط ...

أخ Hasan .. استخدام لغة البرمجه لا علاقة له بالفلسفه (لا أدري ما هي الموضه هذه الأيام التي تقرن كل شيء علمي بفلسفه وراءه) ... هناك Tool ... أستخدمها عندما أراها مناسبة لي ... وغيري قد يحصل عى نفس النتاج بدون استخدام ما استخدمته أنا, وان لم تكن ال Tool جيده فلماذا هي مشموله في ال Syntactical Design للغه؟

مع ملاحظة أن رغد قادمه من خلفية C/C++ وليس Java.

It's hard to stay in such ridiculous situation

#5
Mohammed Akram كتب:
جميل جدا :) أعشق هذا النوع من المواضيع.

مع تعقيب بسيط ...

أخ Hasan .. استخدام لغة البرمجه لا علاقة له بالفلسفه (لا أدري ما هي الموضه هذه الأيام التي تقرن كل شيء علمي بفلسفه وراءه) ... هناك Tool ... أستخدمها عندما أراها مناسبة لي ... وغيري قد يحصل عى نفس النتاج بدون استخدام ما استخدمته أنا, وان لم تكن ال Tool جيده فلماذا هي مشموله في ال Syntactical Design للغه؟

مع ملاحظة أن رغد قادمه من خلفية C/C++ وليس Java.

اخي العزيز, فلسفة بايثون تؤثر على تصميم اللغة, صحيح انه بامكانك ان تبرمج في بايثون و كأنك في جافا, و لكن ما الفائدة اذن من استخدام بايثون؟ استخدم جافا و ريح راسك.

اكتب في مفسر البايثون:

import this

هذه اول مرة اسمع انه اصبح هناك دعم للـ private في بايثون, و هذه الخاصية بصراحة لا تروق لي كثيرا :)

#6

استخدام اى attribute مسبوقة ب2 underscore بيكون مقصود بيها ان private ولكن دا مش واقع

لأن بيتم تحويلها ل

_Classname__attribute

class Point(object):

	def __init__(self, x, y):
		self.__x=x
		self.__y=y

	__str__=lambda self: "<Point (%d, %d)>"%(self.__x, self.__y)

p1=Point(3, 5)
print dir(p1)
print p1
p1._Point__x=0
print p1

اقتباس
['_Point__x', '_Point__y', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']

<Point (3, 5)>

<Point (0, 5)>

بس هو لو حد عمل كدا اكيد يبقة مبرمج رخم :D

فى كل الأحوال اذا ال attribute فى عملية ال set مش بيتم فيها اى اختبارات مجرد بيتم اسناد قيمة فمش هيكون فى اى لزمة لإستخدام get/set معاها

شكل هيكون فى موضوع قريب عن ال descriptors

اضافة مش فاكر الفصل الكام فى الكتاب فيه جزئية عن ال encapsulation وال properties http://programming-fr34ks.net/smf/articles-12/oop-basics/

شكرا رغد!

(map share people)

فضلا لاتقم بمراسلتي من أجل أسئلة لها أقسامها في المنتدى حتى تعم الفائدة على الجميع وللحصول على إجابات أفضل من أعضاء أكثر خبرة.
Weblog
@bitbucket
@xmonader

#7

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

عفواً و شكراً بنفس الوقت لكل الأخوان المشاركين و مداخلاتهم الكريمة

بخصوص الإجابة لأخي حسان لا أملك افضل من إجابة اخي محمد أكرم

و لغة Python عاملينها بدون ما يعملوا حساب للقادمين و القادمات من لغات أخرى ويجب أن تدعم هذه الخصائص لتكون لغة نموذجية و تخدم كل الإحتياجات الموجودة باللغات الأخرى.

(منافسة يعني)

و ربما نضظر لاستعمالن بيوم من الأيام أو اي حدا غيرنا

موفقين يارب

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

درس جميل أختنا رغد ... هل يطبق الدرس على ما قبل python 3؟

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

شكراً اخي محمد

بخصوص الإجابة!

لأ اظن ذلك و لكنني لست متأكدة (ربما)...الدرس و فكرت الدرس من كتاب python 3.0 مش نصياً طبعاً و لكن المفهوم تبع الدرس من هالكتاب.

موفق يارب

bye

[وسط]

♥ Countess ♥

57899411.gif

♥

[/وسط]

#8
اقتباس
و لغة Python عاملينها بدون ما يعملوا حساب للقادمين و القادمات من لغات أخرى ويجب أن تدعم هذه الخصائص لتكون لغة نموذجية و تخدم كل الإحتياجات الموجودة باللغات الأخرى.

لا اختي ليس المطلوب من اللغات الناجحة ان تقلد الخصائص الموجودة في اللغات الاخرى و الا ستكون اللغة عبارة عن كومة غير متناسقة. هناك امور يتم الصاقها بالبرمجة الشيئية oop و هي ليست بالضرورة منها. لغة سمول توك smalltalk و اللتي هي اللغة الام للبرمجة الشيئية لا يوجد فيها (بحسب ما اعرف) اي دعم لقضية private variables

بخصوص انشاء setters/getters لكل المتغيرات في الكلاس, هذه العادة قادمة من سي بلص بلص و جافا, و لكننا لا نحتاجها في بايثون اذا كان الـ getter لا يقوم بشيء اضافي سوى تمرير القيمة كما هي الى المتغير.

المشكلة في جافا مثلا لو كان هناك متغير x و نقوم بالتعامل معه مباشرة:

obj.x = 10;

ثم قررنا تغيير الكلاس و ان لا نسمح لـ x ان تصبح اقل من 0 مثلا, في هذه الحالة سوف نجعل اكس private و نقوم بعمل setter

void setX(int px)
{
if( px > 0 ) x = px;
}

في هذه الحالة يجب ان نغير جميع اجزاء الكود اللتي تتعامل مع x مباشرة و نحولها لاستخدام setX

و لهذا ينصحون بان تقوم بكتابة setX منذ البداية.

و لكن في بايثون, يمكن تحويل المتغير الى property و ان نضع عليه setter/getter من دون تغيير بقية الاكواد اللتي تتعامل معه.

لهذا كما قال الاخ احمد يوسف,

اقتباس
فى كل الأحوال اذا ال attribute فى عملية ال set مش بيتم فيها اى اختبارات مجرد بيتم اسناد قيمة فمش هيكون فى اى لزمة لإستخدام get/set معاها
#9

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

لا نستغني عن هالمفاهيم ابداً ببرامجنا الفاعلة و القوية هندسياً و إلكم مسال كبييير الدوال من هالنوع الموجودين بمكتبة Qt...بقلب كل صنف class.

طبعاً مش لإستعمالات عشوائية و بسيطة لمجرد التعيين بس

شكراً للملاحظة

موفقين يارب

bye

[وسط]

♥ Countess ♥

57899411.gif

♥

[/وسط]

مواضيع مشابهة