الفصل : 9
الجزء : 1
الفصل : ال CLASSES
البرمجة الشيئية (Object-oriented programming أو OOP) هي واحدة من أكثر الطرق فعالية لكتابة البرمجيات. في البرمجة الشيئية، تقوم بكتابة classes التي تمثل الأشياء والمواقف في العالم الحقيقي، وتقوم بإنشاء objects بناءً على هذه classes. عند كتابة class، تقوم بتعريف السلوك العام الذي يمكن أن تمتلكه فئة كاملة من objects.
عندما تقوم بإنشاء objects فردية من class، فإن كل object مجهز تلقائيًا بالسلوك العام؛ ويمكنك بعد ذلك إعطاء كل object الصفات الفريدة التي ترغب فيها. ستُدهش من مدى قدرة البرمجة الشيئية على تمثيل المواقف الحقيقية.
إن إنشاء object من class يُسمى instantiation، وتعمل مع instances من class. في هذا الفصل، ستكتب classes وتُنشئ instances من تلك classes. ستحدد نوع المعلومات التي يمكن تخزينها في instances، وستُعرف الإجراءات التي يمكن اتخاذها مع هذه instances. ستكتب أيضًا classes تقوم بتمديد وظائف classes الموجودة، بحيث يمكن لـ classes المماثلة مشاركة الوظائف العامة، وتتمكن من فعل المزيد بكتابة أقل. ستخزن classes الخاصة بك في modules وستستورد classes المكتوبة بواسطة مبرمجين آخرين في ملفات برامجك.
إن تعلم البرمجة الشيئية سيساعدك على رؤية العالم كما يراه المبرمج. سيساعدك في فهم الكود الخاص بك، ليس فقط ما يحدث سطرًا بسطر، بل أيضًا المفاهيم الأكبر وراءه. إن معرفة المنطق وراء classes سيدربك على التفكير بطريقة منطقية، لتتمكن من كتابة برامج تعالج بشكل فعال أي مشكلة تواجهها.
كما تجعل classes الحياة أسهل لك وللمبرمجين الآخرين الذين ستعمل معهم عند مواجهة تحديات متزايدة التعقيد. عندما تكتب أنت والمبرمجون الآخرون كودًا بناءً على نفس النوع من المنطق، ستتمكنون من فهم أعمال بعضكم البعض. ستجعل برامجك منطقية للأشخاص الذين تعمل معهم، مما يسمح للجميع بإنجاز المزيد.
اذا لم يكن الشرح لديك واضح وما زال صعب , اذا واسمع فيديو المقدم من قناة تعلم ببساطة بالظبط اول 10 دقائق فقط من الفيديو , لانه سيتابع الى لغة C ++ :
https://www.youtube.com/watch?v=aJG-KnmfFxM
إنشاء واستخدام Class
يمكنك نمذجة أي شيء تقريبًا باستخدام classes. لنبدأ بكتابة class بسيط، Dog، الذي يمثل كلبًا، ليس كلبًا واحدًا على وجه التحديد، بل أي كلب. ماذا نعرف عن معظم الكلاب الأليفة؟ حسنًا، جميعها لها اسم وعمر. كما نعلم أن معظم الكلاب تجلس وتدور. هاتان المعلومتان (الاسم والعمر) وهاتان السلوكان (الجلوس والدوران) سيكونان في class Dog لأنهما شائعان لدى معظم الكلاب. سيخبر هذا class بايثون كيفية إنشاء object يمثل كلبًا. بعد كتابة class، سنستخدمه لإنشاء instances فردية، كل منها يمثل كلبًا محددًا.
إنشاء Dog Class
كل instance تم إنشاؤها من class Dog ستخزن اسمًا وعمرًا، وسنمنح كل كلب القدرة على الجلوس (sit()) والتدحرج (roll_over()):
هناك الكثير لنلاحظه هنا، لكن لا تقلق. ستشاهد هذا الهيكل طوال هذا الفصل وستتاح لك الكثير من الوقت للتعود عليه. أولاً، نحدد class يسمى Dog. وفقًا للتقاليد، تشير الأسماء الكبيرة إلى classes في بايثون. لا توجد أقواس في تعريف class لأننا نقوم بإنشاء هذا class من الصفر. بعد ذلك نكتب docstring يصف ما يفعله هذا class.
The __init__() Method
الـ function التي تكون جزءًا من class هي method. كل ما تعلمته عن functions ينطبق على methods أيضًا؛ الاختلاف العملي الوحيد في الوقت الحالي هو طريقة استدعاء methods. الـ __init__() method هي method خاصة يقوم بايثون بتشغيلها تلقائيًا كلما أنشأنا instance جديدة بناءً على class Dog. هذه method لديها شرطان سفليان وشرطان علويان، وهو تقليد يساعد على منع أسماء methods الافتراضية في بايثون من التعارض مع أسماء methods الخاصة بك. تأكد من استخدام شرطين على كل جانب من __init__(). إذا استخدمت شرطًا واحدًا فقط على كل جانب، فلن يتم استدعاء method تلقائيًا عند استخدام class الخاص بك، مما يمكن أن يؤدي إلى أخطاء يصعب تحديدها.
نحدد الـ __init__() method لتحتوي على ثلاث معاملات: self، name، وage. معلمة self مطلوبة في تعريف method، ويجب أن تأتي أولاً، قبل المعاملات الأخرى. يجب تضمينها في التعريف لأنه عندما يستدعي بايثون هذه method لاحقًا (لإنشاء instance من Dog)، فإن استدعاء method سيمرر معلمة self تلقائيًا. كل استدعاء method مرتبط بـ instance يمرر تلقائيًا self، وهي مرجع إلى instance نفسه؛ تمنح instance الفردية الوصول إلى attributes وmethods في class. عندما نقوم بعمل instance من Dog، سيستدعي بايثون الـ __init__() method من class Dog. سنمرر إلى Dog() اسمًا وعمرًا كمعاملات؛ يتم تمرير self تلقائيًا، لذا لا نحتاج إلى تمريره. كلما أردنا إنشاء instance من class Dog، سنقدم قيمًا فقط للمعاملتين الأخيرتين، name وage.
المتغيران اللذان تم تعريفهما في جسم الـ __init__() method كل منهما يحتوي على البادئة self. أي متغير يحتوي على بادئة self يكون متاحًا لكل method في class، وسنتمكن أيضًا من الوصول إلى هذه المتغيرات من خلال أي instance يتم إنشاؤه من class. السطر self.name = name يأخذ القيمة المرتبطة بمعامل name ويعينها للمتغير name، الذي يتم إرفاقه بعد ذلك بـ instance التي يتم إنشاؤها. نفس العملية تحدث مع self.age = age. المتغيرات التي يمكن الوصول إليها من خلال instances بهذه الطريقة تسمى attributes.
ال Dog Class لديها طريقتان أخريان محددتان: sit() وroll_over().
لأن هذه الطرق لا تحتاج إلى معلومات إضافية لتعمل، فإننا نحددها لتحتوي على معلمة واحدة، self. ستتمكن instances التي ننشئها لاحقًا من الوصول إلى هذه الطرق. بعبارة أخرى، ستتمكن من الجلوس والدوران. في الوقت الحالي، sit() وroll_over() لا تقومان بالكثير. إنهما ببساطة تطبعان رسالة تقول إن الكلب يجلس أو يتدحرج. لكن يمكن تمديد المفهوم ليشمل المواقف الواقعية: إذا كان هذا class جزءًا من لعبة حاسوب، فإن هذه الطرق ستحتوي على كود لجعل كلب متحرك يجلس ويتدحرج. إذا كان هذا class مكتوبًا للتحكم في روبوت، فإن هذه الطرق ستوجه الحركات التي تجعل كلبًا روبوتيًا يجلس ويتدحرج.
إنشاء Instance من Class
ملحوظة :
في البرمجة الشيئية (OOP)، كلمة "instance" معناها ببساطة "نسخة" أو "كائن" من الفئة (class).
لما بنعمل class، بنكون عاملين زي قالب أو تصميم (Blueprint) لحاجة معينة. الـclass ده مش حاجة فعلية لسه، هو مجرد تصميم بيوصف الصفات والأفعال اللي الكائنات اللي هنعملها من التصميم ده هتكون عندها.
لكن لما نيجي نستخدم الـclass ده علشان نصنع كائن فعلي، الكائن ده بنسميه "instance".
مثال بسيط
تخيل إنك عندك قالب لصنع عربيات، القالب ده بيقول إن كل عربية هتكون عندها صفات زي اللون والموديل، والأفعال زي التحرك والتوقف.
عمل Class للعربية
class Car:
def __init__(self, color, model):
self.color = color
self.model = model
def start(self):
print(f"{self.color} {self.model} started.")
def stop(self):
print(f"{self.color} {self.model} stopped.")
في المثال ده، عملنا Class اسمه Car بيوصف إيه هي صفات وأفعال أي عربية هنعملها من القالب ده.
عمل Instances من Class العربية
لما نيجي نعمل عربية جديدة باستخدام الـclass اللي عملناه، بنكون عملنا "instance" من الـclass ده:
my_car = Car('red', 'Toyota')
your_car = Car('blue', 'Honda')
فكر في class على أنه مجموعة من التعليمات حول كيفية إنشاء instance. Class Dog هو مجموعة من التعليمات التي تخبر بايثون بكيفية إنشاء instances فردية تمثل كلابًا محددة.
لنقم بإنشاء instance تمثل كلبًا محددًا:
ال Class Dog الذي نستخدمه هنا هو الذي كتبناه للتو في المثال السابق. هنا، نخبر بايثون بإنشاء كلب اسمه 'Willie' وعمره 6 سنوات. عندما يقرأ بايثون هذا السطر، فإنه يستدعي method __init__() في Dog مع المعاملات 'Willie' و6. تقوم method __init__() بإنشاء instance تمثل هذا الكلب المحدد وتعين الاسم والعمر إلى attributes باستخدام القيم التي قدمناها. ثم يعيد بايثون instance تمثل هذا الكلب. نعين تلك instance إلى المتغير my_dog. التسمية التوضيحية مفيدة هنا؛ يمكننا عادةً افتراض أن اسمًا كبيرًا مثل Dog يشير إلى class، واسمًا صغيرًا مثل my_dog يشير إلى instance واحدة تم إنشاؤها من class.
الوصول إلى Attributes
للوصول إلى attributes الخاصة بـ instance، تستخدم التدوين النقطي. نصل إلى قيمة attribute الخاصة بـ my_dog’s name بكتابة:
يتم استخدام التدوين النقطي كثيرًا في بايثون. هذا التركيب يوضح كيف يجد بايثون قيمة attribute. هنا، يبحث بايثون في instance my_dog ثم يجد attribute name المرتبطة بـ my_dog. هذه هي نفس attribute المشار إليها بـ self.name في class Dog. نستخدم نفس النهج للعمل مع attribute age.
المخرجات هي ملخص لما نعرفه عن my_dog:
استدعاء Methods
بعد إنشاء instance من class Dog، يمكننا استخدام التدوين النقطي لاستدعاء أي method تم تعريفها في Dog. لنخبر الكلب بالجلوس والدوران:
لاستدعاء method ، أعط اسم الـinstance (في هذه الحالة، my_dog) والطريقة التي تريد استدعاءها، مفصولة بنقطة. عندما يقرأ Python my_dog.sit()، يبحث عن الmethod sit() في الفئة Dog ويشغل هذا الكود. يفسر Python السطر my_dog.roll_over() بنفس الطريقة. الآن يقوم Willie بما نطلب منه:
هذه الصيغة مفيدة جدًا. عندما يتم إعطاء الattributes والmethod أسماء وصفية مناسبة مثل name و age و sit() و roll_over()، يمكننا بسهولة استنتاج ما من المفترض أن يقوم به كتلة الكود، حتى إذا لم نرها من قبل.
إنشاء عدة Instances
يمكنك إنشاء العديد من الـinstances من class كما تحتاج. لنقم بإنشاء كلب ثانٍ يسمى your_dog:
في هذا المثال، ننشئ كلبًا اسمه Willie وكلبًا آخر اسمه Lucy. كل كلب هو instance منفصل مع مجموعة من الصفات الخاصة به، قادرة على نفس مجموعة الأفعال:
حتى إذا استخدمنا نفس الاسم والعمر للكلب الثاني، فإن Python ستنشئ instance منفصل من الفئة Dog. يمكنك إنشاء العديد من الـinstances من فئة واحدة كما تحتاج، طالما تعطي كل instance اسم متغير فريد أو يشغل مكانًا فريدًا في قائمة أو قاموس.
جرّب بنفسك
تمرين 9-1. Restaurant: أنشئ فئة تُسمى Restaurant. يجب أن تقوم طريقة __init__() في Restaurant بتخزين صفتين: restaurant_name و cuisine_type. أنشئ method تُسمى describe_restaurant() تطبع هاتين المعلومتين، و method تُسمى open_restaurant() تطبع رسالة تشير إلى أن المطعم مفتوح.
أنشئ instance يُسمى restaurant من ال class الخاصة بك . اطبع الattributes فرديًا، ثم استدعِ كلتا الmethods .
تمرين 9-2. Three Restaurants: ابدأ بفئتك من التمرين 9-1. أنشئ ثلاث instances مختلفة من الفئة، واستدعِ describe_restaurant() لكل instance.
تمرين 9-3. Users: أنشئ فئة تُسمى User. أنشئ صفتين تُسميان first_name و last_name، ثم أنشئ عدة صفات أخرى تُخزن عادةً في ملف تعريف المستخدم. أنشئ طريقة تُسمى describe_user() تطبع ملخصًا لمعلومات المستخدم. أنشئ طريقة أخرى تُسمى greet_user() تطبع تحية شخصية للمستخدم.
أنشئ عدة instances تمثل مستخدمين مختلفين، واستدعِ كلتا الطريقتين لكل مستخدم.
العمل مع الفئات (Classes) والـinstances
يمكنك استخدام الفئات لتمثيل العديد من المواقف في العالم الواقعي. بمجرد كتابة فئة، ستقضي معظم وقتك في العمل مع الـinstances التي تُنشأ من هذه الفئة. إحدى أولى المهام التي ستود القيام بها هي تعديل الصفات المرتبطة بـinstance معين. يمكنك تعديل صفات instance مباشرةً أو كتابة طرق تحدث الصفات بطرق معينة.
فئة Car
لنكتب فئة جديدة تمثل سيارة. فئتنا ستخزن معلومات حول نوع السيارة التي نعمل عليها، وستحتوي على طريقة تلخص هذه المعلومات:
في الفئة Car، نُعرِّف طريقة __init__() بمعلمة self أولاً ❶، تمامًا كما فعلنا مع الفئة Dog. كما نعطيها ثلاث معلمات أخرى: make و model و year. طريقة __init__() تأخذ هذه المعلمات وتعينها إلى الصفات التي ستكون مرتبطة بالـinstances التي تُنشأ من هذه الفئة. عندما ننشئ instance جديد من الفئة Car، سنحتاج إلى تحديد make و model و year للـinstance.
نُعرِّف طريقة تُسمى get_descriptive_name() ❷ تضع سنة السيارة وmake وmodel في سلسلة نصية مرتبة تصف السيارة بشكل أنيق. هذا سيوفر علينا عناء طباعة قيمة كل صفة بشكل فردي. للعمل مع قيم الصفات في هذه الطريقة، نستخدم self.make و self.model و self.year. خارج الفئة، ننشئ instance من الفئة Car ونعينه إلى المتغير my_new_car ❸. ثم نستدعي get_descriptive_name() لنرى نوع السيارة التي لدينا:
لجعل الفئة أكثر إثارة، دعنا نضيف صفة تتغير بمرور الوقت. سنضيف صفة تخزن المسافة المقطوعة للسيارة.
تعيين قيمة افتراضية لصفة (Attribute)
عند إنشاء instance، يمكن تعريف الصفات دون تمريرها كمعلمات. يمكن تعريف هذه الصفات في طريقة __init__()، حيث يتم تعيين قيمة افتراضية لها.
دعنا نضيف attribute تُسمى odometer_reading التي تبدأ دائمًا بقيمة 0. سنضيف أيضًا طريقة (method) تُسمى read_odometer() التي تساعدنا في قراءة عداد المسافات لكل سيارة:
هذه المرة، عندما يستدعي Python طريقة __init__() لإنشاء instance جديد، فإنه يخزن قيم make و model و year كصفات، كما فعل في المثال السابق. ثم ينشئ Python صفة جديدة تُسمى odometer_reading ويعين قيمتها الأولية إلى 0 ❶. لدينا أيضًا طريقة جديدة تُسمى read_odometer() ❷ التي تجعل من السهل قراءة عداد المسافات للسيارة.
تبدأ سيارتنا بمسافة مقطوعة قدرها 0:
نادرًا ما تُباع السيارات بمسافة مقطوعة قدرها 0 أميال، لذا نحتاج إلى طريقة لتغيير قيمة هذه الصفة.
تعديل قيم الصفات
يمكنك تغيير قيمة صفة بثلاث طرق: يمكنك تغيير القيمة مباشرةً من خلال instance، تعيين القيمة من خلال طريقة (method)، أو زيادة القيمة (إضافة مقدار معين إليها) من خلال method. دعونا نلقي نظرة على كل من هذه الطرق.
تعديل قيمة صفة مباشرةً
أبسط طريقة لتعديل قيمة صفة هي الوصول إلى الصفة مباشرةً من خلال instance. هنا نقوم بتعيين قراءة العداد إلى 23 مباشرةً:
نستخدم التدوين النقطي للوصول إلى صفة odometer_reading للسيارة، ونعين قيمتها مباشرةً. هذا السطر يخبر Python بأخذ الـinstance my_new_car، والعثور على الصفة odometer_reading المرتبطة به، وتعيين قيمة هذه الصفة إلى 23:
في بعض الأحيان سترغب في الوصول إلى الصفات مباشرةً مثل هذا، ولكن في أحيان أخرى سترغب في كتابة طريقة تحدث القيمة نيابةً عنك.
تعديل قيمة صفة من خلال طريقة (Method)
يمكن أن يكون من المفيد وجود طرق تحدث صفات معينة نيابةً عنك. بدلاً من الوصول إلى الصفة مباشرةً، تمرر القيمة الجديدة إلى طريقة تتولى التحديث داخليًا.
إليك مثال يوضح طريقة تُسمى update_odometer():
التعديل الوحيد على Car هو إضافة update_odometer(). هذه الطريقة تأخذ قيمة mileage وتعينها إلى self.odometer_reading. باستخدام الـinstance my_new_car، نستدعي update_odometer() مع 23 كمعلمة ❶. هذا يعين قراءة العداد إلى 23، وread_odometer() تطبع القراءة:
يمكننا توسيع طريقة update_odometer() للقيام بعمل إضافي كلما تم تعديل قراءة العداد. دعنا نضيف بعض المنطق للتأكد من أن أحدًا لا يحاول الرجوع بقراءة العداد:
الآن، تتحقق update_odometer() من أن القراءة الجديدة منطقية قبل تعديل الصفة. إذا كانت القيمة المقدمة لـmileage أكبر من أو تساوي قراءة العداد الحالية، self.odometer_reading، يمكنك تحديث قراءة العداد إلى المسافة الجديدة ❶. إذا كانت المسافة الجديدة أقل من القراءة الحالية، ستحصل على تحذير بأنك لا يمكنك الرجوع بقراءة العداد ❷.
زيادة قيمة صفة من خلال طريقة
أحيانًا سترغب في زيادة قيمة صفة بمقدار معين، بدلاً من تعيين قيمة جديدة تمامًا. قل أننا اشترينا سيارة مستعملة ووضعنا 100 ميل عليها بين وقت الشراء ووقت تسجيلها. إليك طريقة تسمح لنا بتمرير هذا المقدار الإضافي وإضافة تلك القيمة إلى قراءة العداد:
تأخذ الطريقة الجديدة increment_odometer() مقدار الأميال، وتضيف هذه القيمة إلى self.odometer_reading. أولاً، ننشئ سيارة مستعملة، my_used_car ❶. نضبط عدادها إلى 23,500 عن طريق استدعاء update_odometer() وتمرير 23_500 ❷. أخيرًا، نستدعي increment_odometer() ونمرر 100 لإضافة الـ100 ميل التي قطعناها بين شراء السيارة وتسجيلها:
يمكنك تعديل هذه الطريقة لرفض الزيادات السلبية حتى لا يستخدم أحد هذه الوظيفة للرجوع بقراءة العداد أيضًا.
ملاحظة
يمكنك استخدام طرق مثل هذه للتحكم في كيفية تحديث مستخدمي برنامجك لقيم مثل قراءة العداد، ولكن أي شخص لديه حق الوصول إلى البرنامج يمكنه تعيين قراءة العداد لأي قيمة عن طريق الوصول إلى الصفة مباشرةً. يتطلب الأمان الفعال انتباهاً دقيقًا للتفاصيل بالإضافة إلى الفحوصات الأساسية مثل تلك المعروضة هنا.
جرب بنفسك :
تمرين 9-4. عدد الزبائن المخدومين:
ابدأ ببرنامجك من التمرين 9-1. أضف صفة جديدة تسمى number_served بقيمة افتراضية 0. قم بإنشاء instance تسمى restaurant من هذه الفئة. اطبع عدد الزبائن الذين خدمهم المطعم، ثم قم بتغيير هذه القيمة واطبعها مرة أخرى.
أضف طريقة تسمى set_number_served() التي تسمح لك بتعيين عدد الزبائن الذين تم خدمتهم. استدعِ هذه الطريقة بعدد جديد واطبع القيمة مرة أخرى.
أضف طريقة تسمى increment_number_served() التي تسمح لك بزيادة عدد الزبائن الذين تم خدمتهم. استدعِ هذه الطريقة بأي عدد تحبه يمكن أن يمثل عدد الزبائن الذين تم خدمتهم في يوم عمل، مثلاً.
تمرين 9-5. محاولات تسجيل الدخول:
أضف صفة تسمى login_attempts إلى فئة User من التمرين 9-3 . اكتب طريقة تسمى increment_login_attempts() التي تزيد قيمة login_attempts بمقدار 1. اكتب طريقة أخرى تسمى reset_login_attempts() التي تعيد تعيين قيمة login_attempts إلى 0.
قم بإنشاء instance من فئة User واستدعِ increment_login_attempts() عدة مرات. اطبع قيمة login_attempts للتأكد من أنها زادت بشكل صحيح، ثم استدعِ reset_login_attempts(). اطبع login_attempts مرة أخرى للتأكد من أنها أعيد تعيينها إلى 0.
النهاية
نكون هنا انتهينا من الجزء 1 من الفصل 9 من منهج تعلم Python من كتاب python crash course بالعربية
واذا واجهتك اي مشكلة في الفهم او ما شابه , يمكنك على الفور الذهاب الى المجتمع الخاص بنا في Telegram للمناقشة والتواصل معنا من هنا
او اذا واجهتك مشكلة في الموقع او تريد اجابة سريعة يمكنك الذهاب الى اخر صفحة في الموقع ستجد صفحة اتصل بنا موجودة يمكنك ارسالة لنا مشكلتك , وسيتم الرد عليها بسرعة جدا ان شاء الله
ويمكنك الأنضمام الى المجتمع Hidden Lock بالكامل مع جميع قنواته للأستفادة في اخر الأخبار في عالم التقنية وايضا الكتب بالمجان والكورسات والمقالات من خلال الرابط التالي لمجموعة القنوات من هنا
يمكنك ايضا متابعتنا في منصات X او Twitter سابقا , لمشاهدة الاخبار والمقالات السريعة والمهمة من
وفقط كان معكم sparrow مقدم هذه الشهادة من فريق Hidden Lock