لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 09/22/24 في كل الموقع
-
مرحبا هل تخصص تطوير الويب له مستقبل؟ اما انه سيصبح غير مطلوب. وايضا ماهي اكثير التخصصات البرمجية المطلوبة في سوق العمل حاليا وايضا في المستقبل؟2 نقاط
-
السلام عليكم اي هي اداة nmap ؟ وكيف استخدمها في باثيون ؟ ومين الايستخدمها يعني هل هي ففط خاص بمجال الامن السبيراني ؟2 نقاط
-
السلام عليكم عن تعرف loop في باثيون بنكتب كده for i in range(n): pass ولكن في مطورين بدل ما يكتبو متغبر i بيكتبو كده for _ in range(n): pass فا اي الفرق ؟2 نقاط
-
السلام عليكم كيف اطبق علي Abstract factory بلغة باثيون ؟2 نقاط
-
السلام عليكم هو هنا ام بعمل اثنين loop بتشتغل ازي ؟ for i in range(5): for n in range(6): pass2 نقاط
-
السلام عليكم انا ادرس في كورس بايثون و لقد انهيت الحلقات التكرارية ، اريد مصادر لحل تمارين و تطوير ال problem solving تزامنا مع جدولي في دراسة اللغة1 نقطة
-
1 نقطة
-
السلام عليكم احد عنده خبرة في bug bounty انا توني في البدايه وابي اتعلم ذا المجال عشان احل مسائل عليه عندي نقاط تحتاج اجابة ١- من وين ابدأ ووش افضل مصدر ترشحونه علماً اني من النوع التشتتي احتاج مصدر امشي عليه كامل ٢-كيف اتدرب ٣-ايش هي المواقع الي عندها مسائل لذا الموضوع شكراً1 نقطة
-
Nmap اختصار لـ Network Mapper وهي أداة مفتوحة المصدر لمسح الشبكات واكتشاف الأجهزة والخدمات التي تعمل عليها، وتعتبر من أهم الأدوات المستخدمة في مجال أمن المعلومات. ولكنها تستخدم أيضًا في العديد من المجالات الأخرى مثل تحديد الأجهزة المتصلة بالشبكة، بما في ذلك عناوين IP الخاصة بها ونظام التشغيل المفتوح، تحديد المنافذ المفتوحة على الأجهزة المتصلة بالشبكة، والبروتوكولات والخدمات التي تعمل عليها، تحديد نظام التشغيل الذي يعمل على الأجهزة المتصلة بالشبكة، تحديد إصدار الخدمات التي تعمل على المنافذ المفتوحة، وتعمل مع أدوات أخرى للبحث عن الثغرات الأمنية في الأجهزة والخدمات. وعلى الرغم من أن Nmap تستخدم بشكل أساسي في مجال أمن المعلومات، إلا أنها ليست مقتصرة على ذلك المجال، فكما أشرت تستطيع استخدامها في العديد من المجالات الأخرى ومنها إدارة الشبكات لمراقبة الشبكة واكتشاف الأجهزة الجديدة والتحقق من تكوين الأجهزة، ولاختبار التطبيقات والتحقق من المنافذ التي تستخدمها.1 نقطة
-
1 نقطة
-
assert للتحقق من الشروط التي يجب أن تكون صحيحة ليعمل البرنامج بشكل صحيح، أي هي أداة لاكتشاف الأخطاء خلال مرحلة التطوير، وتُشير إلى وجود خطأ في منطق البرنامج إن فشل الشرط. ولو كان الشرط في assert خاطئًا، فإنها تُطلق استثناء من نوع AssertionError، مما يؤدي إلى إيقاف البرنامج عن العمل ما لم يتم التعامل مع الاستثناء. أما if للتحكم في تدفق البرنامج من خلال شروط قد تكون صحيحة أو خاطئة، بالتالي هي جزء أساسي من منطق البرنامج وتُستخدم لاتخاذ قرارات مختلفة حسب حالة البرنامج. وفي حال كان الشرط في if خاطئًا، فإنها تتجاهل كتلة التعليمات التابعة لها وتنتقل إلى السطر التالي من الكود.1 نقطة
-
أداة nmap تعتبر من الأدوات المعروفة في مجال الأمن السيبراني خاصة في مراقبة الشبكة و تحليلها و معرفة البروتات المفتوحة في النظام الذي تقوم بعمل فحص عليه إضافة يوجد مكتبة في بايثون في الشبكات مثل socket و python-nmap تستخدم أغلبية الأحيان في إختبار إختراق المواقع أو الأنظمة لإكتشاف معلومات حول النظام أو الموقع من نوعية البورات و البورتات المفتوحة و نوعية السرفر إلخ إضافة أنها من الأداوت الأساسية و المشهورة في إختبارات إختبار إختراق مثل إختبار شهادة oscp و هي تعتبر شهادة رائد في مجال الامن الهجومي و الفريق الأحمر إضافة أنه يوجد نسخة ذو واجهة رسومية لأداة nmap بإسم zenmap إذا لديك نظام تشغيل كالي لينكس أكتب التالي sudo apt-get search zenmap بعد أن يظهر لك إسم باللون الأزرق تأخذ الإسم و تحمله عبر الطريقة التالية sudo apt-get install tool-name1 نقطة
-
1 نقطة
-
السلام عليكم ورحمة الله وبركاته اردت ان اعمل نظاما بسيطا ب جافا سكريبت يقوم بتحويل الساعة من نظام 24 ساعة الي 12 والعكس صحيح ايضا فقمت بكتابة الكود التالي ونجح معي وذهبت الي منصة تحديات كودر هب لكن لم ينجح معي واظهر لي ان الكود غير صحيح فهل هناك خطا ام ماذا وايضا ما هي افضل طريقة ممكنة لتحويل نظام الساعات واتمني ان يكون هناك شرح مع الاكواد function convert_time(time) { if (time.startsWith("13") || time.startsWith("14") || time.startsWith("15") || time.startsWith("16") || time.startsWith("17") || time.startsWith("18") || time.startsWith("19") || time.startsWith("20") || time.startsWith("21") || time.startsWith("22") || time.startsWith("23")) { time = time.split(":") let d = parseInt(time[0]) time.push("pm") let h = String(time).replace(",", ":") let g = h.replace(",", " ") let z = g.replace(g[0], "") let u = z.replace(g[1], "") let y = parseInt(d) - 12 + u return y }; if (time.startsWith("00")) { time = time.split(":") let d = parseInt(time[0]) time.push("pm") let h = String(time).replace(",", ":") let g = h.replace(",", " ") let z = g.replace(g[0], "") let u = z.replace(g[1], "") let y = parseInt(d) + 12 + u return y } // write your code here if (time.startsWith("12") && time.endsWith("am")) { time = time.split(":") time = String(time).replace("pm", "") time = String(time).replace("12", "00") time = String(time).replace("am", "") } else if (time.startsWith("12") && time.endsWith("pm")) { time = time.split(":") time[0] = +time[0] time = String(time).replace("pm", "") time = String(time).replace("am", "") }; if (time.endsWith("pm")) { time = time.split(":") time[0] = +time[0] + 12 time = String(time).replace("pm", "") } else { time = time.split(":") time = String(time).replace("am", "") }; return String(time).replace(",", ":") }1 نقطة
-
تابع المقصود به Method أو طريقة وتلك دالة تكون داخل كائن أو Class صنف حيث نصل لتلك الدالة من خلال النقطة . أما الدالة خارج الكائن أو الصنف تسمى دالة فقط.1 نقطة
-
مرحبا, I've just completed this project, and I would love to hear your honest opinions and any suggestions for further improvement. Thank you git clone : https://github.com/Hamadabcn/Automated_teller_machine.git Automated_teller_machine.rar I may have changed the PIN during testing, so if the default '1234' doesn't work, try '1981'. I've been switching it to ensure everything functions properly Notice how when you quit and reopen the program, all the transaction history is saved, and you can view it by simply pressing 'Show History'1 نقطة
-
_ ليس لتخزين قيمة هنا، بل هي مثل placeholder للأرقام التي في دالة range أي تمثل كل رقم في تلك الدالة ثم يتم التكرار على عدد تلك الأرقام، بالتالي لا نحتاج إلى كتابة i فنحن لن نستخدم تلك القيمة بل نضعها فقط لكي تعمل حلقة for حيث يجب وجود متغير يمثل قيمة في كل تكرار. وسواء استخدمت i أو _ لا مشكلة، لكن i أفضل في حال ستقوم باستخدامها داخل الحلقة فهو حرف يسهل قراءته.1 نقطة
-
جربت هذه الأكواد الثلاثة ولم تعمل يعني لم تظهر خلفية ال Frame باللون الأحمر ما المشكلة في هذه الاكواد؟ يعني استخدمت الخواص place,pack,grid ولم تجدي نفعاً _____________________________ from tkinter import * moha = Tk() moha.geometry("300x200") frame = Frame(moha, bg="red") frame.place(x=1,y=1) moha.mainloop() _____________________________ from tkinter import * moha = Tk() moha.geometry("300x200") frame = Frame(moha, bg="red") frame.pack() moha.mainloop() _____________________________ from tkinter import * moha = Tk() moha.geometry("300x200") frame = Frame(moha, bg="red") frame.grad(row=0,culomn=0) moha.mainloop()1 نقطة
-
تمام بس بنسب الذكرا عندي i اتخزن قيمه ولكن عندي _ هل اتخزين قيمه في الذكرا ؟1 نقطة
-
ببساطة عندما تكتب for i in range(n): فهذا يعني أنك قد تستخدم المتغير i داخل الحلقة لكن عندما تكتب for _ in range(n): فهذا يعني أنك لا تحتاج المتغير وتستخدم الحلقة فقط لتكرار شيء معين عددا من المرات فهذا _ هو مجرد رمز للتوضيح بأنك لا تهتم بقيمة المتغير. وهذا مثال توضيحي: for i in range(5): print(i) هنا ستستخدم i لطباعة الأرقام بينما هنا: for _ in range(5): print("Hello") فأنت لا تحتاج إلى عداد، فقط تكرر طباعة Hello خمسة مرات.1 نقطة
-
إذا استخدمت i أو أي اسم آخر كمؤشر في الحلقة، فهذا يعني أنك قد تنوي استخدام هذا المتغير داخل الحلقة بهذا الشكل: for i in range(5): print(i) هنا يتم استخدام i لطباعة الأرقام من 0 إلى 4. أما عندما تستخدم _ فهذا يعني أنك لا تنوي استخدام المتغير داخل الحلقة، وأنك تريد فقط تنفيذ الكود داخل الحلقة بدون الحاجة لاستخدام المؤشر، و يعتبر _ هنا تعبير متعارف عليه للإشارة إلى أن المتغير لن يُستخدم. for _ in range(5): print("Hsoub") فهنا يتم تكرار الكود داخل الحلقة 5 مرات، لكن لا يتم استخدام المتغير _.1 نقطة
-
نمط ال Abstract Factory هو أحد أنماط التصميم المستخدمة في البرمجة الكائنية لتطبيقه يمكن أن نأخذ مثالا بيسيط وعمليا لكن قبل ذلك يجب أن نفهم أولا كيفية تطبيق النمط أولا نقوم بتحديد واجهتين (أو فئات مجردة) تمثل العائلات المختلفة من الكائنات ثم يجب إنشاء الفئات التي تنفذ هذه الواجهات بعدها يأتي الدور على إنشاء المصنع أين يجب أن تنشئ مصنعا Factory يمكنه إنشاء كائنات من الفئات المحددة وهذا مثال لنفترض أننا نريد إنشاء واجهات مستخدم مختلفة لنظامين وليكونا نظام Windows ونظام macOS: from abc import ABC, abstractmethod # واجهة للزر class Button(ABC): @abstractmethod def paint(self): pass # واجهة لواجهة المستخدم class GUIFactory(ABC): @abstractmethod def create_button(self) -> Button: pass # تنفيذ للزر في Windows class WindowsButton(Button): def paint(self): return "Windows Button" # تنفيذ للزر في macOS class MacOSButton(Button): def paint(self): return "MacOS Button" # مصنع Windows class WindowsFactory(GUIFactory): def create_button(self) -> Button: return WindowsButton() # مصنع macOS class MacOSFactory(GUIFactory): def create_button(self) -> Button: return MacOSButton() # استخدام المصنع def client_code(factory: GUIFactory): button = factory.create_button() print(button.paint()) # اختيار المصنع windows_factory = WindowsFactory() client_code(windows_factory) mac_factory = MacOSFactory() client_code(mac_factory) هذه الشيفرة ستستخدم نموذج المصنع المجرد (Abstract Factory) لإنشاء أزرار لواجهة المستخدم لنظامي التشغيل بحيث يحتوي على واجهات تحدد كيفية إنشاء الأزرار (Button و GUIFactory)، وفئات تقوم بتنفيذ هذه الواجهات (مثل WindowsButton و MacOSButton) ويقوم كل مصنع سواء WindowsFactory أو MacOSFactory بإنشاء نوع محدد من الأزرار في الأخير الدالة client_code تستخدم هذه المصانع لإنشاء الأزرار ثم طباعتها.1 نقطة
-
1 نقطة
-
في البداية، يبدأ المتغير i في الحلقة الخارجية بالقيمة 0 وبمجرد دخول الحلقة الخارجية، تبدأ الحلقة الداخلية بالعمل في حين المتغير n يأخذ القيم من 0 إلى 5 أي أن مجموع التكرارات هو 6 وبعد انتهاء الحلقة الداخلية لجميع القيم الممكنة للمتغير n أي من 0 إلى 5 تزداد قيمة i في الحلقة الخارجية لتصبح 1 مرة أخرى، يتم تشغيل الحلقة الداخلية كاملة بنفس الطريقة، والمتغير n يأخذ القيم من 0 إلى 5 ويستمر هذا النمط حتى تصل الحلقة الخارجية إلى قيمتها النهائية أي i تصل إلى 4.1 نقطة
-
1 نقطة
-
1 نقطة
-
1 نقطة
-
نعم أعلم ذلك لقد حصلت علي الشهادة الخاصة بتطبيقات بايثون. ونظرا لدرجة الاحترافية العالية التي تقدمها الاكاديمية وطريقة الشرح استطعت النجاح في مقابلات العمل الخاصة ب django ,flask واتمني ان تضيف الاكاديمية مسارا خاص ب fast api مع بعض المشاريع العملية . فهل سيكون قريبا مسارا خاصاً ب fast api ?1 نقطة
-
1 نقطة
-
و عليكم السلام، ال design patterns هو عبارة عن أنماط لتنظيم الكود البرمجي لتحقيق وظائف معينة بشكل أفضل. بالتالي هو ليس خاصًا بال oop، و إن كان أغلب الأنماط الخاصة بال design patterns تستعمل ال oop فهي تستعمله و ليست "خاصة" به. تحياتي.1 نقطة
-
السلام عليكم هي الشبكات العصبيه بديل لخورزميات التقلدي لنماذج تعلم الاله ؟ وامتي استخدم الشبكات العصبيه وامتي استخدم الخورزميات التقلدي ؟1 نقطة
-
و عليكم السلام، يمكنك اعتبارها تطورًا لها، ففي الخوارزميات التقليدية يجب اختيار الميزات features بشكل يدوي، بينما في الشبكات العصبية فإنها تتعلم ذلك بنفسها. بشكل عام في حال وجود بيانات كثيرة فإن الأفضل دائمًا هو استعمال الشبكات العصبية، أو شبكات التعلم العميق بشكل عام. بينما في حال وجود بيانات قليلة فالخوارزميات التقليدية غالبًا ما تعطي نتائج أفضل. و يبقى الأمر يخضع للاختبار قليلًا خاصة في حال كنت لست متأكد فيما إذا كان لديك بيانات كثيرة للمهمة أم لا. تحياتي.1 نقطة
-
مرحبا انا ما زلت اتعلم جافا سكربت وانتهيت من الاساسيات حيث درست المصفوفات والدوال والكائنات...الخ ولكنني لم انتهي من الدورة. مؤخرا تعرفت على مهاراة اسمها problem solving هل ينبغي علئ تعلمها اثناء تعلم الدورة ام بعدما انتهي من هذه الدورة؟1 نقطة
-
مرحبًا، يمكنك إضافة الصورة من حسابك على حسوب، فهو حساب عام لكل مواقع حسوب من بينها الأكاديمية. يمكنك الوصول إلى إعدادات حسابك من هنا: https://accounts.hsoub.com/settings تحياتي.1 نقطة
-
مرحبًا، لا يوجد حاليًا مسار خاص ب fast api ضمن دورة بايثون، حيث يتم استعمال django و flask بشكل أساسي. تحياتي.1 نقطة
-
مرحبًا، الكود الخاص بك يحتوي على الكثير من if..else و هذا غير جيد بشكل عام، أنت تقوم بالاعتماد على معرفتك الدقيقة للخرج و كتابة كل شيء بشكل مباشر في الكود بدل الاعتماد على قدرة الكود على كتابة الأفكار العامة. من غير الجيد أن أعطيك الكود مباشرة، و كما يبدو أنه لديك خبرة في البرمجة لذلك سأشرح لك كيفية القيام بالتحويل و عليك كتابة الكود بنفسك حتى تتعلم و تكتسب خبرة أكبر. سنقوم بكتابة تابع في البداية و لندعوه decodeTime يقوم بأخذ الساعة (بدون معرفة فيما إذا كانت بنظام 12 أو 24) و يعيد لنا 3 متغيرات (يمكنك إعادتهم ضمن مصفوفة مثلا) الأول يمثل الساعة و الثاني يمثل الدقيقة و الثالث يمثل الثواني، طبعًا كل هذه المتغيرات من النمط integer. أيضًا نكتب تابع آخر يقوم بالعملية بشكل عكسي و سندعوه encodeTime، بحيث يأخذ مصفوفة من قيم الساعة و يعيد الساعة على شكل سلسلة نصية. ثم سنقوم بالتحقق فيما إذا كان الكود يتبع لنظام ال 12 أو 24 عن طريق التحقق فيما إذا كان ينتهي ب pm, am، هذا قمت به أنت في مرحلة من مراحل كودك لذلك أعتقد أنك تستطيع القيام بذلك. بعد التحقق من ذلك سيكون لدينا إما تحقق الشرط أو لا. في حال تحقق الشرط أي نحن في نظام ال 12 ساعة، نقوم بإزالة am أو pm من الكود (مع معرفة أيهما موجود)، و نقوم بتمرير ما تبقى و الذي يمثل الساعة الى التابع decodeTime الذي سبق و كتبناه بحيث يعيد لنا هذه الأمور على شكل أعداد صحيحة. الآن كل ما علينا القيام به هو إضافة 12 إلى المتغير الذي يحمل رقم الساعات في حال كان الوقت pm، أو لا نضيف أي شيء في حال كان am. ثم نقوم بتمرير القيم الجديدة للمصفوفة إلى التابع encodeTime بحيث يقوم بإعادتها على شكل سلسلة نصية. حاليًا قمنا بشكل صحيح بالتحويل من نظام 12 ساعة إلى نظام 24 ساعة بسهولة. أما في الحالة العكسية، فنقوم في البداية باستدعاء التابع decodeTime مباشرة (بما أنه ليس لدينا am, pm في الوقت)، و نقوم بالتحقق فيما إذا كانت الساعات أكبر من 12، في تلك الحالة نقوم بطرح 12 منها، و نضع التوقيت أنه pm و إلا لا نقوم بطرح أي شيء و نضع التوقيت أنه am. نقوم بتمرير المصفوفة الخاصة بالوقت إلى الدالة encodeTime للحصول على الوقت، من ثم نقوم بإضافة am أو pm إلى نهاية السلسلة النصية الناتجة. بشكل عام كما تلاحظ الكود ليس صعب، فكرة كتابة تابع يقوم بتقسيم الوقت و إرجاعه على شكل مصفوفة من الأعداد الصحيحة تسهل عليك العمل بشكل كبير. تحياتي.1 نقطة
-
لا توجد طريقة أفضل جميع الطرق تمكنك من الوصول إلى البيانات الخاصة بالطلب ولكن بإختلاف نوع الطلب وإختلاف مكان البيانات . $request->name_std: هذه هي الطريقة المباشرة لجلب البيانات من الطلب إذا كان لديك متغير باسم name_std في الطلب يمكنك الوصول إليه بهذه الطريقة. $request->input('name_std'): نستخدم تلك الطريقة لجلب قيمة معينة للبيانات من الطلب بغض النظر عن طريقة الإرسال سواء POST أو GET وهنا سنحضر name_std. $request->post('name_std'):نستخدم تلك الطريقة لجلب البيانات المرسلة عبر طريقة POST فقط إذا كان لديك نموذج يرسل البيانات عبر POST يمكنك استخدام هذه الطريقة ولا تعمل تلك الطريقة إذا كان الطلب GET. $request->get('name_std'):نستخدم تلك الطريقة لجلب البيانات المرسلة عبر طريقة GET فقط هذه الطريقة مناسبة إذا كنت تتعامل مع روابط أو استعلامات GET ولا تعمل تلك الطريقة إذا كان الطلب POST . $request['name_std']: هذه الطريقة بديلة لجلب البيانات من الطلب وتشبه في عملها لـ $request->input('name_std'). $request->query('name_std'): نستخدم تلك الطريقة لجلب القيم من سلسلة الاستعلام (query string) في الروابط فإذا أردت إسترجاع البيانات من الرابط URL . تلخيصا لما سبق إذا كنت تتعامل مع نموذج يرسل بيانات عبر POST، استخدم post أو input و إذا كنت تتعامل مع بيانات من URL أو استعلام GET، استخدم get أو query و للوصول المباشر للمتغير، يمكنك استخدام $request->name_std أو $request['name_std']. اختيار الطريقة يعتمد على كيفية إرسال البيانات وما تحتاجه من الطلب كما أخبرتك.1 نقطة
-
بما أنك تمتلك فكرة عن البرمجة وأساسياتها نعم يمكنك تجاوز مرحلة سكراتش، لأنه بيئة برمجة موجهة بالأساس للمبتدئين لتعلم المفاهيم الأساسية بطريقة بصرية وسهلة، و بما أنك أتقنت هذه المفاهيم بالفعل، فلست بحاجة إلى العودة إليها، و كنصيحة يمكنك الإطلاع عليها مع تسريع الفيديو فقط حتى تأخذ أفكار جديدة ربما لم تسمع بها من قبل أو لم تدرسها1 نقطة
-
ستحتاج إلى إنشاء عنصر أب ووضع جميع العناصر به، ثم إنشاء عنصر أب حاوي لكل 5 عناصر وتعيين display : flex له ثم تعديل إتجاه عرض العناصر إلى column بدلاً من row وذلك بواسطة: flex-direction: column; ولفصل الـ 5 عناصر عن بعضهم قم بوضع margin بينهم، أو يمكن تعيين diplay : flex للعنصر الأب الحاوي لهم جميعًا ثم تعيين خاصية gap بقيمة 20 px مثلاً.1 نقطة
-
و عليكم السلام يحيى، هذا الرقم هو سمعتك في الموقع، و تزيد السمعة كلما قام أحد بالتفاعل مع تعليقاتك أو أسئلتك. هذا يظهر نسبيًا نشاطك ضمن الأكاديمية. مثلًا لقد قمت الآن بالتفاعل مع سؤالك الحالي، و يمكنك أن ترى أن سمعتك أصبحت 24 بدلًا من 23. تحياتي.1 نقطة
-
نعم يمكنك ذلك فأغلب الدورات هنا يكون القسم الأول منها عبارة عن تعليم الأساسيات للغة البرمجة التي سيتم إستعمالها و بالتالي لن تجد مشكلة في هذا، بالنسبة للعمل من الأيباد نعم يمكنك ذلك كبداية فقط و ستعتمد بشكل أكثر على google colab و لكن هناك بعض الأدوات أو البرامج التي تتطلب حاسوبا للتنفيذ العملي، لذا يفضل امتلاك حاسوب للاستفادة الكاملة من جميع الدروس. في الأخير بإمكانك العثور على فرص عمل في مجال الذكاء الاصطناعي والعمل عن بعد بعد اكتساب المهارات اللازمة، و بالتأكيد سيتكفل فريق من الأكاديمية بمرافقتك في هذا الأمر، فهناك طلب متزايد على خبراء الذكاء الاصطناعي والمحللين، ويمكنك العمل في مجالات متعددة مثل تحليل البيانات، تطوير النماذج، والتعلم الآلي.1 نقطة
-
تُسِّهل البرمجة الكائنية كتابة شيفرات قابلة لإعادة الاستخدام وتجنب التكرار في مشاريع التطوير. إحدى الآليات التي تحقق بها البرمجة الكائنية هذا الهدف هي مفهوم الوراثة (inheritance)، التي بفضلها يمكن لصنفٍ فرعي (subclass) استخدام الشيفرة الخاصة بصنف أساسي (base class، ويطلق عليه «صنف أب» أيضًا) موجود مسبقًا. سيستعرض هذا الدرس بعض الجوانب الرئيسية لمفهوم الوراثة في بايثون، بما في ذلك كيفية إنشاء الأصناف الأساسية (parent classes) والأصناف الفرعية (child classes)، وكيفية إعادة تعريف (override) التوابع والخاصيات، وكيفية استخدام التابع super()، وكيفية الاستفادة من الوراثة المتعددة (multiple inheritance). ما هي الوراثة؟ تقوم الوراثة على استخدام شيفرة صنف معين في صنف آخر أي يرث صنف يراد إنشاؤه شيفرة صنف آخر. يمكن تمثيل مفهوم الوراثة في البرمجة بالوراثة في علم الأحياء تمامًا، فالأبناء يرثون خاصيات معينة من آبائهم. ويمكن لطفل أن يرث طول والده أو لون عينيه بالإضافة إلى خاصيات أخرى جديدة خاصة فيه. كما يتشارك الأطفال نفس اسم العائلة الخاصة بآبائهم. ترث الأصناف الفرعية (subclasses، تُسمى أيضًا *الأصناف الأبناء [child classes]) التوابع والمتغيرات من *الأصناف الأساسية* (base classes، تسمى أيضًاالأصناف الآباء [parent classes]). مثلًا، قد يكون لدينا صنف أساسي يسمى Parent يحتوي متغيرات الأصناف last_name و height و eye_color، والتي سيرثها الصنف الابن Child. لمَّا كان الصنف الفرعي Child يرث الصنف الأساسي Parent، فبإمكانه إعادة استخدام شيفرة Parent، مما يسمح للمبرمج بكتابة شيفرة أوجز، وتقليل التكرار. الأصناف الأساسية تشكل الأصناف الأساسية أساسًا يمكن أن تستند إليه الأصناف الفرعية المُتفرِّعة منها، إذ تسمح الأصناف الأساسية بإنشاء أصناف فرعية عبر الوراثة دون الحاجة إلى كتابة نفس الشيفرة في كل مرة. يمكن تحويل أي صنف إلى صنف أساسي، إذ يمكن استخدامه لوحده، أو جعله قالبًا (نموذجًا). لنفترض أّنّ لدينا صنفًا أساسيًا باسم Bank_account، وصنفين فرعيين مُشتقين منه باسم Personal_account و Business_account. ستكون العديد من التوابع مشتركة بين الحسابات الشخصية (Personalaccount) والحسابات التجارية (Businessaccount)، مثل توابع سحب وإيداع الأموال، لذا يمكن أن تنتمي تلك التوابع إلى الصنف الأساسي Bank_account. سيكون للصنف Business_account توابع خاصة به، مثل تابع مخصص لعملية جمع سجلات ونماذج الأعمال، بالإضافة إلى متغير employee_identification_number موروث من الصنف الأب. وبالمثل، قد يحتوي الصنف Animal على التابعين eating() و sleeping()، وقد يتضمن الصنف الفرعي Snake تابعين إضافيين باسم hissing() و slithering() خاصين به. دعنا ننشئ صنفًا أساسيًا باسم Fish لاستخدامه لاحقًا أساسًا لأصناف فرعية تمثل أنواع الأسماك. سيكون لكل واحدة من تلك الأسماك أسماء أولى وأخيرة، بالإضافة إلى خصائص مميزة خاصة بها. سننشئ ملفًا جديدًا يسمى fish.py ونبدأ بالباني، والذي سنعرّف داخله متغيري الصنف first_name و last_name لكل كائنات الصنف Fish، أو أصنافه الفرعية. class Fish: def __init__(self, first_name, last_name="Fish"): self.first_name = first_name self.last_name = last_name القيمة الافتراضية للمتغير last_name هي السلسلة النصية "Fish"، لأننا نعلم أنّ معظم الأسماك سيكون هذا هو اسمها الأخير. لنُضف بعض التوابع الأخرى: class Fish: def __init__(self, first_name, last_name="Fish"): self.first_name = first_name self.last_name = last_name def swim(self): print("The fish is swimming.") def swim_backwards(self): print("The fish can swim backwards.") لقد أضفنا التابعين swim() و swim_backwards() إلى الصنف Fish حتى يتسنى لكل الأصناف الفرعية استخدام هذه التوابع. ما دام أنّ معظم الأسماك التي ننوي إنشاءها ستكون عظمية (أي أنّ لها هيكلا عظميًا) وليس غضروفية (أي أن لها هيكلًا غضروفيًا)، فيمكننا إضافة بعض الخاصيات الإضافية إلى التابع __init__(): class Fish: def __init__(self, first_name, last_name="Fish", skeleton="bone", eyelids=False): self.first_name = first_name self.last_name = last_name self.skeleton = skeleton self.eyelids = eyelids def swim(self): print("The fish is swimming.") def swim_backwards(self): print("The fish can swim backwards.") لا يختلف بناء الأصناف الأساسية عن بناء أي صنف آخر، إلا أننا نصممها لتستفيد منها الأصناف الفرعية المُعرّفة لاحقًا. الأصناف الفرعية الأصناف الفرعية هي أصناف ترث كل شيء من الصنف الأساسي. هذا يعني أنّ الأصناف الفرعية قادرة على الاستفادة من توابع ومتغيرات الصنف الأساسي. على سبيل المثال، سيتمكن الصنف الفرعي Goldfish المشتق من الصنف Fish من استخدام التابع swim() المُعرّف في Fish دون الحاجة إلى التصريح عنه. يمكننا النظر إلى الأصناف الفرعية على أنها أقسام من الصنف الأساسي. فإذا كان لدينا صنف فرعي يسمى Rhombus (معيّن)، وصنف أساسي يسمى Parallelogram (متوازي الأضلاع)، يمكننا القول أنّ المعين (Rhombus) هو متوازي أضلاع (Parallelogram). يبدو السطر الأول من الصنف الفرعي مختلفًا قليلًا عن الأصناف غير الفرعية، إذ يجب عليك تمرير الصنف الأساسي إلى الصنف الفرعي كمعامل: class Trout(Fish): الصنف Trout هو صنف فرعي من Fish. يدلنا على هذا الكلمةُ Fish المُدرجة بين قوسين. يمكننا إضافة توابع جديدة إلى الأصناف الفرعية، أو إعادة تعريف التوابع الخاصة بالصنف الأساسي، أو يمكننا ببساطة قبول التوابع الأساسية الافتراضية باستخدام الكلمة المفتاحية pass، وهو ما سنفعله في المثال التالي: ... class Trout(Fish): pass يمكننا الآن إنشاء كائن من الصنف Trout دون الحاجة إلى تعريف أي توابع إضافية. ... class Trout(Fish): pass terry = Trout("Terry") print(terry.first_name + " " + terry.last_name) print(terry.skeleton) print(terry.eyelids) terry.swim() terry.swim_backwards() لقد أنشأنا كائنًا باسم terry من الصنف Trout، والذي سيستخدم جميع توابع الصنف Fish وإن لم نعرّفها في الصنف الفرعي Trout. يكفي أن نمرر القيمة "Terry" إلى المتغير first_name، أما المتغيرات الأخرى فقد جرى تهيئتها سلفًا. عند تنفيذ البرنامج، سنحصل على المخرجات التالية: Terry Fish bone False The fish is swimming. The fish can swim backwards. لننشئ الآن صنفًا فرعيًا آخر يعرّف تابعًا خاصا به. سنسمي هذا الصنف Clownfish. سيسمح التابع الخاص به بالتعايش مع شقائق النعمان البحري: ... class Clownfish(Fish): def live_with_anemone(self): print("The clownfish is coexisting with sea anemone.") دعنا ننشئ الآن كائنًا آخر من الصنف Clownfish: ... casey = Clownfish("Casey") print(casey.first_name + " " + casey.last_name) casey.swim() casey.live_with_anemone() عند تنفيذ البرنامج، سنحصل على المخرجات التالية: Casey Fish The fish is swimming. The clownfish is coexisting with sea anemone. تُظهر المخرجات أنّ الكائن casey المستنسخ من الصنف Clownfish قادر على استخدام التابعين __init__() و swim() الخاصين بالصنف Fish، إضافة إلى التابع live_with_anemone() الخاص بالصنف الفرعي. إذا حاولنا استخدام التابع live_with_anemone() في الكائن Trout، فسوف يُطلق خطأ: terry.live_with_anemone() AttributeError: 'Trout' object has no attribute 'live_with_anemone' ذلك أنَّ التابع live_with_anemone() ينتمي إلى الصنف الفرعي Clownfish فقط، وليس إلى الصنف الأساسي Fish. ترث الأصناف الفرعية توابع الصنف الأساسي الذي اشتُقَّت منه، لذا يمكن لكل الأصناف الفرعية استخدام تلك التوابع. إعادة تعريف توابع الصنف الأساسي في المثال السابق عرّفنا الصنف الفرعي Trout الذي استخدم الكلمة المفتاحية pass ليرث جميع سلوكيات الصنف الأساسي Fish، وعرّفنا كذلك صنفًا آخر Clownfish يرث جميع سلوكيات الصنف الأساسي، ويُنشئ أيضًا تابعًا خاصًا به. قد نرغب في بعض الأحيان في استخدام بعض سلوكيات الصنف الأساسي، ولكن ليس كلها. يُطلَق على عملية تغيير توابع الصنف الأساسي «إعادة التعريف» (Overriding). عند إنشاء الأصناف الأساسية أو الفرعية، فلا بد أن تكون لك رؤية عامة لتصميم البرنامج حتى لا تعيد تعريف التوابع إلا عند الضرورة. سننشئ صنفًا فرعيًا Shark مشتقًا من الصنف الأساسي Fish، الذي سيمثل الأسماك العظمية بشكل أساسي، لذا يتعين علينا إجراء تعديلات على الصنف Shark المخصص في الأصل للأسماك الغضروفية. من منظور تصميم البرامج، إذا كانت لدينا أكثر من سمكة غير عظمية واحدة، فيُستحب أن ننشئ صنفًا خاصًا بكل نوع من هذين النوعين من الأسماك. تمتلك أسماك القرش، على عكس الأسماك العظمية، هياكل مصنوعة من الغضاريف بدلاً من العظام. كما أنّ لديها جفونًا، ولا تستطيع السباحة إلى الوراء، كما أنها قادرة على المناورة للخلف عن طريق الغوص. على ضوء هذه المعلومات، سنعيد تعريف الباني __init__() والتابع swim_backwards(). لا نحتاج إلى تعديل التابع swim() لأنّ أسماك القرش يمكنها السباحة. دعنا نلقي نظرة على هذا الصنف الفرعي: ... class Shark(Fish): def __init__(self, first_name, last_name="Shark", skeleton="cartilage", eyelids=True): self.first_name = first_name self.last_name = last_name self.skeleton = skeleton self.eyelids = eyelids def swim_backwards(self): print("The shark cannot swim backwards, but can sink backwards.") لقد أعدنا تعريف المعاملات التي تمت تهيئتها في التابع __init__()، فأخذ المتغير last_name القيمة "Shark"، كما أُسنِد إلى المتغير skeleton القيمة "cartilage"، فيما أُسنِدَت القيمة المنطقية True إلى المتغير eyelids. يمكن لجميع نُسخ الصنف إعادة تعريف هذه المعاملات. يطبع التابع swim_backwards() سلسلة نصية مختلفة عن تلك التي يطبعها في الصنف الأساسي Fish، لأنّ أسماك القرش غير قادرة على السباحة للخلف كما تفعل الأسماك العظمية. يمكننا الآن إنشاء نسخة من الصنف الفرعي Shark، والذي سيستخدم التابع swim() الخاص بالصنف الأساسي Fish: ... sammy = Shark("Sammy") print(sammy.first_name + " " + sammy.last_name) sammy.swim() sammy.swim_backwards() print(sammy.eyelids) print(sammy.skeleton) عند تنفيذ هذه الشيفرة، سنحصل على المخرجات التالية: Sammy Shark The fish is swimming. The shark cannot swim backwards, but can sink backwards. True cartilage لقد أعاد الصنف الفرعي Shark تعريف التابعين __init__() و swim_backwards() الخاصين بالصنف الأساسي Fish، وورث في نفس الوقت التابع swim() الخاص بالصنف الأساسي. الدالة super() يمكنك باستخدام الدالة super() الوصول إلى التوابع الموروثة التي أُعيدت كتابتها. عندما نستخدم الدالة super()، فإننا نستدعي التابع الخاص بالصنف الأساسي لاستخدامه في الصنف الفرعي. على سبيل المثال، قد نرغب في إعادة تعريف جانب من التابع الأساسي وإضافة وظائف معينة إليه، ثم بعد ذلك نستدعي التابع الأساسي لإنهاء بقية العمل. في برنامج خاص بتقييم الطلاب مثلًا، قد نرغب في تعريف صنف فرعي Weighted_grade يرث الصنف الأساسي Grade، ونعيد فيه تعريف التابع calculate_grade() الخاص بالصنف الأساسي من أجل تضمين شيفرة خاصة بحساب التقدير المرجّح (weighted grade)، مع الحفاظ على بقية وظائف الصنف الأساسي. عبر استدعاء التابع super()، سنكون قادرين على تحقيق ذلك. عادة ما يُستخدم التابع super() ضمن التابع __init__()، لأنّه المكان الذي ستحتاج فيه على الأرجح إلى إضافة بعض الوظائف الخاصة إلى الصنف الفرعي قبل إكمال التهيئة من الصنف الأساسي. لنضرب مثلًا لتوضيح ذلك، دعنا نعدّل الصنف الفرعي Trout. نظرًا لأنّ سمك السلمون المرقَّط من أسماك المياه العذبة، فلنضف متغيرًا اسمه water إلى التابع __init__()، ولنُعطه القيمة "freshwater"، ولكن مع الحفاظ على باقي متغيرات ومعاملات الصنف الأساسي: ... class Trout(Fish): def __init__(self, water = "freshwater"): self.water = water super().__init__(self) ... لقد أعدنا تعريف التابع __init__() في الصنف الفرعي Trout، وغيرنا سلوكه موازنةً بالتابع __init__() المُعرَّف سلفًا في الصنف الأساسي Fish. لاحظ أننا استدعينا التابع __init__() الخاص بالصنف Fish بشكل صريح ضمن التابع __init__() الخاص بالصنف Trout،. بعد إعادة تعريف التابع، لم نعد بحاجة إلى تمرير first_name كمعامل إلى Trout، وفي حال فعلنا ذلك، فسيؤدي ذلك إلى إعادة تعيين freshwater بدلاً من ذلك. سنُهيِّئ بعد ذلك الخاصية first_name عن طريق استدعاء المتغير في الكائن خاصتنا. الآن يمكننا استدعاء متغيرات الصنف الأساسي التي تمت تهيئتها، وكذلك استخدام المتغير الخاص بالصنف الفرعي: ... terry = Trout() # تهيئة الاسم الأول terry.first_name = "Terry" # super() الخاص بالصنف الأساسي عبر __init__() استخدام print(terry.first_name + " " + terry.last_name) print(terry.eyelids) # المعاد تعريفها في الصنف الفرعي __init__() استخدام print(terry.water) # الخاص بالصنف الأساسي swim() استخدام التابع terry.swim() سنحصل على المخرجات التالية: Terry Fish False freshwater The fish is swimming. تُظهر المخرجات أنّ الكائن terry المنسوخ من الصنف الفرعي Trout قادر على استخدام المتغير water الخاص بتابع الصنف الفرعي __init__()، إضافة إلى استدعاء المتغيرات first_name و last_name و eyelids الخاصة بالتابع __init__() المُعرَّف في الصنف الأساسي Fish. يسمح لنا التابع super() المُضمن في بايثون باستخدام توابع الصنف الأساسي حتى بعد إعادة تعريف تلك التوابع في الأصناف الفرعية. الوراثة المُتعدِّدة (Multiple Inheritance) المقصود بالوراثة المتعددة هي قدرة الصنف على أن يرث الخاصيات والتوابع من أكثر من صنف أساسي واحد. هذا من شأنه تقليل التكرار في البرامج، ولكنه يمكن أيضًا أن يُعقِّد العمل، لذلك يجب استخدام هذا المفهوم بحذر. لإظهار كيفية عمل الوراثة المتعددة، دعنا ننشئ صنفًا فرعيًا Coral_reef يرث من الصنفين Coral و Sea_anemone. يمكننا إنشاء تابع في كل صنف أساسي، ثم استخدام الكلمة المفتاحية pass في الصنف الفرعي Coral_reef: class Coral: def community(self): print("Coral lives in a community.") class Anemone: def protect_clownfish(self): print("The anemone is protecting the clownfish.") class CoralReef(Coral, Anemone): pass يحتوي الصنف Coral على تابع يسمى community()، والذي يطبع سطرًا واحدًا، بينما يحتوي الصنف Anemone على تابع يسمى protect_clownfish()، والذي يطبع سطرًا آخر. سنُمرِّر الصنفين كلاهما بين قوسين في تعريف الصنف CoralReef، ما يعني أنه سيرث الصنفين معًا. دعنا الآن ننشئ كائنًا من الصنف CoralReef: ... great_barrier = CoralReef() great_barrier.community() great_barrier.protect_clownfish() الكائن great_barrier مُشتقٌ الصنف CoralReef، ويمكنه استخدام التوابع من كلا الصنفين الأساسيين. عند تنفيذ البرنامج، سنحصل على المخرجات التالية: Coral lives in a community. The anemone is protecting the clownfish. تُظهِر المخرجات أنَّ التوابع من كلا الصنفين الأساسيين استُخدِما بفعالية في الصنف الفرعي. تسمح لنا الوراثة المُتعدِّدة بإعادة استخدام الشيفرات البرمجية المكتوبة في أكثر من صنف أساسي واحد. وإذا تم تعريف التابع نفسه في أكثر من صنف أساسي واحد، فإنّ الصنف الفرعي سيستخدم التابع الخاص بالصنف الأساسي الذي ظهر أولًا في قائمة الأصناف المُمرَّرة إليه عند تعريفه. رغم فوائدها الكثيرة وفعاليتها، إلا أنَّ عليك توخي الحذر في استخدام الوراثة المُتعدِّدة، حتى لا ينتهي بك الأمر بكتابة برامج مُعقَّدة وغير مفهومة للمبرمجين الآخرين. خلاصة تعلمنا في هذا الدرس كيفية إنشاء أصناف أساسية وفرعية، وكيفية إعادة تعريف توابع وخاصيات الأصناف الأساسية داخل الأصناف الفرعية باستخدام التابع super()، إضافة إلى مفهوم الوراثة المتعددة. الوراثة هي إحدى أهم ميزات البرمجة الكائنية التي تجعلها متوافقة مع مبدأ DRY (لا تكرر نفسك)، وهذا يحسن إنتاجية المبرمجين، ويساعدهم على تصميم برامج فعالة وواضحة. هذه المقالة جزء من سلسة مقالات حول تعلم البرمجة في بايثون 3. ترجمة -وبتصرّف- للمقال Understanding Class Inheritance in Python 3 لصاحبته Lisa Tagliaferri اقرأ أيضًا المقالة التالية: كيفية تطبيق التعددية الشكلية (Polymorphism) على الأصناف المقالة السابقة: فهم متغيرات الأصناف والنسخ في بايثون 3 المرجع الشامل إلى تعلم لغة بايثون كتاب البرمجة بلغة بايثون1 نقطة
-
المُزخرفات من أعظم مميزات لغة بايثون، إذ تساعدك على بناء برنامجك باحترافية أكثر موفرة طريقة بسيطة لإضافة خاصيات جديدة للدالة. وهي ببساطة دوال تستطيع أن تعدل على دوال أخرى. تذكير ببعض المفاهيم الأساسية إذا لم تكن تعرف شيئا عن الدوال في لغة بايثون فيجب عليك العودة للدرس السابق الدوال في بايثون قبل أن تكمل قراءة هذا الدرس. تُعتبر الدوال في لغة بايثون كائنات من نوع الفئة الأولى أو First class objects. ما يعني أنّنا نستطيع القيام بالعديد من العمليات، وهي كالتالي: يُمكنك تعريف دالة داخل دالة أخرى يُمكنك أن تستدعي دالة داخل أخرى يُمكنك أن تقوم بتمرير دالة كمُعامل لدالة أخرى يُمكنك أن تُسند دالة لمُتغير يُمكنك إرجاع دالة داخل دالة أخرى بما أنّ المُزخرفات مُجرّد دوال فعلينا أن نبدأ من الأساس، لاحظ الدالة التالية: def say_hello(): print 'Hello!' عند استدعاء الدالة ستُطبع القيمة Hello على الشاشة، هذا ليس بالأمر المُعقد، الآن ماذا لو أردنا أن نعدل الدالة في جزء آخر من البرنامج لكي تطبع أشياء أخرى وتؤدي أغراضا أخرى قبل استدعاء الدالة أو بعد ذلك؟ يُمكن أن نعدّل الدالة مُباشرة، لكن هذا الأمر سيغير من طريقة سير البرنامج، إذ نريد أن نعدل الدالة في منطقة واحدة فقط من البرنامج وليس في كامل البرنامج، هذه المسألة تُحل بالمُزخرفات، وكما يدل اسمها فهي دوال تُزيّن وتُزخرف الدالة الأصلية، أي تُضيف عليها مهاما أخرى. سننشئ لهذه الدالة الآن مُزخرفا Decorator يقوم بطباعة Before قبل تنفيذ الدالة و After بعد تنفيذ الدالة، وذلك دون تعديل الدالة مُباشرة. انظر المثال التالي: def decorator(function): def function_decorator(): print 'Before' function() print 'After' return function_decorator الشيفرة أعلاه عبارة عن دالة تقبل دالة أخرى (الدالة التي نرغب بزَخرَفَتِها أو تزيينها) كمُعامل وبعدها نقوم بإنشاء دالة داخل هذه الدالة لطباعة القيمة Before ثم استدعاء الدالة الأصلية (المُعامل) بعدها طباعة After وأخيرا إرجاع الدالة الجديدة (وهي نُسخة مزخرفة من الدالة الأصلية). بعدها يُمكننا أن نستخدم هذا المُزخرف لزخرفة أي دالة مهما كانت، انظر المثال التالي: # -*- coding: utf-8 -*- def decorator(function): # إنشاء الدالة المسؤولة عن الزخرفة def function_decorator(): # إنشاء الدالة التي ستكون نسخة مزخرفة من الدالة المُمرّرة في كمُعامل print 'Before' # طباعة جملة قبل تنفيذ الدالة function() # استدعاء الدالة print 'After' return function_decorator # إرجاع الدالة مُزَخْرَفَةً def say_hello(): # إنشاء دالة عادية print 'Hello!' say_hello = decorator(say_hello) # زخرفة الدالة say_hello() # استدعاء النُسخة المُزخرفة من الدالة توفر لنا لغة بايثون طريقة أكثر مرونة لزخرفة الدوال، وهي بوضع اسم المُزخرف مسبوقا بالحرف @ قبل تعريف الدالة. أي أنّ السّطر التالي: def say_hello(): print 'Hello!' say_hello = decorator(say_hello) # زخرفة الدالة يُمكن أن يكون كالتالي: @decorator def say_hello(): # إنشاء دالة عادية print 'Hello!' وبالتالي سنتمكن من زخرفة أي دالة نرغب بزخرفتها كالتالي: @decorator def say_hello(): print 'Hello!' @decorator def say_hi(): print 'Hi!' @decorator def say_name(): print 'Abdelhadi!' say_hello() say_hi() say_name() عند تنفيذ الشيفرة أعلاه ستكون المخرجات كالتالي: Before Hello! After Before Hi! After Before Abdelhadi! After مُلاحظة: إذا كانت للدالة معاملات فما عليك إلا استخدام args* التي سبق وتحدثنا عنها في الدرس السابق. # -*- coding: utf-8 -*- def decorator(function): # إنشاء الدالة المسؤولة عن الزخرفة def function_decorator(*args): # إنشاء الدالة التي ستكون نسخة مزخرفة من الدالة المُمرّرة كمُعامل print 'Before' # طباعة جملة قبل تنفيذ الدالة function(*args) # استدعاء الدالة print 'After' return function_decorator # إرجاع الدالة مُزَخْرَفَةً لاحظ الدالتين function_decorator و function. أمثلة على المزخرفات في لغة بايثون إذا فهمت مبدأ المزخرفات فستستطيع أن تتعامل مع الدوال بمرونة عالية، وإليك بعض الأمثلة لاستخدام المُزخرفات لتأدية بعض المهام البسيطة: حساب مدة تنفيذ دالة إذا فهمت جيدا مبدأ المُزخرفات فستلاحظ بأنّك تستطيع تنفيذ مهام قبل تنفيذ الدالة ومهام بعد تنفيذها، ومما سبق نستنتج بأنّنا نستطيع أن نقوم بحفظ الوقت الحالي في مُتغير ثم تنفيذ الدالة وبعدها نقوم بحساب الفرق بين الوقت السابق والوقت الحالي، ما سيُرجع المُدة المُستغرقة لتنفيذ الدالة. البرنامج التالي مثال على مُزخرف لحساب مُدة دالة تطبع الجملة !Hello World مليون مرّة. # -*- coding: utf-8 -*- import time # جلب مكتبة الوقت لاستعمال دوال الوقت def function_time(function): def function_decorator(*args): start_time = time.time() # الحصول على وقت البداية function(*args) end_time = time.time() # الحصول على الوقت بعد نهاية التنفيذ # طباعة اسم الدالة والفرق بين وقت البداية ووقت النهاية print '%s function took %0.3f s' % (function.func_name, (end_time - start_time)) return function_decorator # إرجاع الدالة مُزَخْرَفَةً # زخرفة الدالة المسؤولة عن الطباعة مليون مرة @function_time def print_million_times(): for i in range(0, 1000000): print 'Hello World! 1,000,000 times!' print_million_times() البرنامج أعلاه سيطبع الجملة مليون مرة ثم يعرض الوقت المُستغرق لإنجاز العملية. الجملة الأخيرة ستكون شيئا كالتّالي: print_million_times function took 69.584 s ملاحظات: نستعمل التابع func_name للحصول على اسم الدالة المُمررة كمعامل، ويكون على شكل سلسلة نصية. نستعمل الجملة time.time للحصول على الوقت بالثواني، عدد الثواني الذي تنتجه الجملة هو عدد الثواني الذي مرّ منذ سنة 1970. يُمكنك استعمال هذا المُزخرف مع أي دالة تريد فقط اكتب اسم المُزخرف مسبوقا بالحرف @ ثم عرف الدالة بعده، وستحصل على الوقت المُستغرق لتنفيذ الدالة. حساب عدد مرات استدعاء دالة يُمكننا أن نستخدم المُزخرفات للحصول على عدد المرات التي استدعيت فيها دالة ما في برنامج مُعيّن، بحيث يحمل متغير قيمة العدد صفر، وفي كل مرة تستدعى فيها الدالة، فإن المُتغير يحمل القيمة مع زيادة بالعدد واحد، انظر المثال التالي. # -*- coding: utf-8 -*- # متغير العد n = 0 # المُزخرف def call_times(function): def decorated(): function() # استدعاء الدالة global n # جعل مُتغير العدّ عالميا n += 1 # زيادة قيمة المُتغير print 'Function was called', n, 'times' # طباعة قيمة المُتغير return decorated @call_times # زخرفة الدالة def func(): # إنشاء الدالة print 'Hello!' # استدعاء الدالة func() func() func() func() مُخرجات البرنامج أعلاه ستكون كالتالي: Hello! Function was called 1 times Hello! Function was called 2 times Hello! Function was called 3 times Hello! Function was called 4 times يُمكنك إصلاح الجمل من الناحية اللغوية بإضافة بعض العبارات الشرطية للبرنامج. إنشاء مزخرف لتنفيذ دالة عند تحقق شرط معين فقط يُمكنك أن تستعمل دالة تسجيل الدخول التي قُمنا بإنشائها كمُزخرف للدوال التي تحتاج لأن يكون المُستخدم مُسجلا دخوله. مثلا لنقل بأنّنا نريد أن نعرض على المُستخدم عدة خيارات بعضها يحتاج إلى تسجيل دخول المُستخدم وبعضها لا. الخيارات كالتّالي: تسجيل مُستخدم جديد (تسجيل الدخول غير مطلوب) طباعة جملة عشر مرات ( تسجيل الدخول غير مطلوب) الحصول على الوقت الحالي ( تسجيل الدخول غير مطلوب) طباعة اسم المُستخدم (تسجيل الدخول مطلوب) رؤية معلومات الحساب (تسجيل الدخول مطلوب) تعديل كلمة المرور (تسجيل الدخول مطلوب) مبدأ عمل البرنامج سيكون كالتالي: إنشاء الدوال المسؤولة عن الخيارات عرض الخيارات على المُستخدم زخرفة الدوال التي تطلب تسجيل المُستخدم بمُزخرف تسجيل الدخول المُزخرف سيتحقق من أنّ المُستخدم قد سجل دخوله، إذا كان الأمر كذلك، تنفّذ الدالة وإذا لم يتحقق الشرط فلا تنفذ. لنقل بأنّ اسم مُزخرف التحقق من تسجيل الدخول هو is_user_logged_in، ستكون الدوال التي تطلب تسجيل الدخول مُزَخْرَفَةً كالتالي: @if_user_logged_in def account_info(): print 'Username:', username, 'Password:', password تمارين تمرين 1 أنشئ دالة للجمع بين عددين، وبعدها أنشئ مُزخرفا يقوم بمُضاعفة النتيجة. تمرين 2 أنشئ دالة للحصول على قيم من المُستخدم وقم بزخرفة لطباعة جملة ترحيب قبل استدعاء الدالة وجملة توديع بعد استدعاءها. تمرين 3 أكمل البرنامج الخاص بالمثال الثالث (إنشاء مُزخرف لتنفيذ دالة عند تحقق شرط مُعين فقط). تفاصيل التمرين موجودة بالمثال.1 نقطة