اذهب إلى المحتوى

Ali Haidar Ahmad

الأعضاء
  • المساهمات

    1068
  • تاريخ الانضمام

  • تاريخ آخر زيارة

  • عدد الأيام التي تصدر بها

    43

كل منشورات العضو Ali Haidar Ahmad

  1. كلاهما يستخدم لمحاربة (أو معالجة) مشكلة الضبط الزائد Overfitting. L1 ( L1 lasso or norm): يقوم بمحاربة ال OF عن طريق تصغير قيم الأوزان المرتبطة بالميزات feature الأقل أهمية باتجاه ال 0، مما يجعل تأثير بعض ال feature مهمل لأنه يجعل قيم بعض الأوزان صفرية تماماً، ويمكن اعتبار ذلك نوعاً من أنواع اختيار الميزات feature selection، ويعتمد على إضافة حد جديد الى تابع الكلفة (يُسمى معاقبة penalty) يمثل مجموع القيم المطلقة للأوزان مضروباً بمعامل تحكم لمدا (زيادتها تؤدي إلى زيادة تأثير هذه العملية وتصغيرها يؤدي إلى العكس، وهي قيمة بين ال 0 وال 1 وتعتبر من المعاملات العليا HyperParameter التي يجب ضبطها). المعادلة المعبرة عنه: أي أنها تعتمد على إضافة مجموع القيم المطلقة للأوزان مضروباً بمعامل تحكم (لمدا)، إلى تابع الكلفة المستخدم. L2 (L2 ridge): يقوم بمحاربة ال OF عن طريق تصغير قيم الأوزان ولكن لا يجعلها صفرية، ويعتمد على إضافة حد جديد إلى تابع الكلفة يمثل مجموع مربعات الاوزان مضروبا بمعامل تحكم لمدا. المعادلة المعبرة عنه: أي أنها تعتمد على إضافة مجموع مربعات للأوزان مضروباً بمعامل تحكم (لمدا)، إلى تابع الكلفة المستخدم. هناك فروق أخرى يمكن استنتاجها من هذا الكلام ،مثل أن L1 أكثر متانة من L2 بسبب قدرته على التعامل مع القيم الشاذة، في حين أن L2 يعاني من مشكلة القيم الشاذة (أو المتطرفة). أيضاً L1 يقوم ضمنيّاً بعملية feature selection، وهذا قد يكون له أثر سلبي لبعض المهام، بينما L2 لا يقوم بذلك أبداً. يعتبر أيضاً L1 تمثيل متناثر Sparse لأن عدد الأصفار يزداد نتيجة تصفير بعض الأوزان على عكس L2 الذي يعتبر كثيف Dense.
  2. بالنسبة لقراءة ملف نصي، فيمكنك قراءته كما ذكر سامح، والآن سأتحدث عن الجزء الثاني من سؤالك وهو تشفير النص. هناك العديد من الطرق لتشفير النص، سأذكر بعضها: التشفير الجمعي أو تشغير قيصر Additive cipher: في هذه الطريقة يُعطى كل حرف من أحرف الأبجدية قيمة رقمية تسند اليه حسب ترتيبه، كما في الجدول التالي: تؤخذ قيمة كل حرف من النص ويُجمع مع مفتاح التشفير ليكون الناتج هو الحرف المقابل في النص المشفر، وفق المعادلة التالية: C = (M + K) mod n النص المشفر = (النص الأصلي + مفتاح التشفير) باقي القسمة على n، حيث أن n تمثل عدد أحرف الأبجدية (في المثال أعلاه 36).وعملية فك التشفير هي عملية معاكسة لعملية التشفير، وبالتالي للقيام بعملية فك التشفير الجمعي نقوم بحساب النظير الجمعي لمفتاح التشفير ويُجمع مع رقم محرف النص المشفر ليكون الناتج هو الحرف المقابل في النص الأصلي، وفق المعادلة التالية: M = (C - K) mod 26 المشفر الجدائي Multiplicative cipher: بشكل مشابه للمشفر الجمعي، لكن هنا بدلاً من الجمع يكون جداء. C=(M*k) mod n لكن توجد هناك شروط على المفتاح، وهو أن يكون أولياً مع عدد أحرف الأبجدية. ويكون فك التشفير من خلال عكس العملية السابقة: M=(C*k^-1) mod n المشفر Affine: وهو مشفر يجمع بين الطريقتين السابقتين،وعليه فإن المُشفرين السابقين هما حالات خاصة من المشفر Affine ويتم التشفير وفقاً للمعادلة التالية: C=(M*k1+k2) mod n عندما تكون k1=1، يتحول إلى مُشفّر جمعي، وعندما k2=0، يتحول لمُشفّر ضربي. الكود التالي هو تحقيق للمشفر Affine، قمت سابقاً بكتابته، ويمكنك استخدامه لتشفير وفك تشفير النصوص: import numpy as np import math # تعريف الأبجدية alphabet1=['a', 'b', 'c', 'd','e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',0,1,2,3,4,5,6,7,8,9] # تعريف تابع مساعد لإيجاد النظير الضربي def extendEuclidean(a, b, s1=1, s2=0, t1=0, t2=1): if b: r=a%b return extendEuclidean(b, r, s2, s1-s2*(a//b), t2, t1-t2*(a//b)) return a, s1, t1 التابع التالي يقوم بعملية التشفير المطلوبة: 1. الوسيط الأول هو النص المطلوب تشفيره. 2. الوسيط الثاني هو الأبجدية التي تتعامل معها. 3. الوسيط الثالث هو قيمة المفتاح k1 (مفتاح الجداء). 4. الوسيط الرابع هو مفتاح الجمع k2. 5. الوسيط الخامس نضعه على True في حال كنت تريد إجراء تشفير Affine أو تشفير ضربي وذلك بغية التحقق من صلاحية مفتاح التشفير الذي تريد استخدامه. # تعريف تابع التشفير def affineEncoder(text,alphabet,kmul=1,kadd=0,isAffineOrMul=False): n=len(alphabet) if isAffineOrMul: if math.gcd(n,kmul)!=1: print("invalid key") return False index=np.arange(n) result=[] cipherDict1 =dict(zip(alphabet, index)) cipherDict2 =dict(zip(index,alphabet)) for i in text.lower(): if i.isdigit(): i=int(i) result.append(str(cipherDict2[(cipherDict1[i]*kmul+kadd)%n])) return "".join(result) التابع التالي هو تابع فك التشفير: # تابع فك التشفير def affineDencoder(text,alphabet,kmul=1,kadd=0,isAffineOrMul=False): n=len(alphabet) if isAffineOrMul: _,kmul,_=extendEuclidean(kmul,n) index=np.arange(n) result=[] cipherDict1 =dict(zip(alphabet, index)) cipherDict2 =dict(zip(index,alphabet)) for i in text.lower(): if i.isdigit(): i=int(i) result.append(str(cipherDict2[((cipherDict1[i]-kadd)*kmul)%n])) return "".join(result) على سبيل المثال: # mul Encoder # zend سأشفر الكلمة التالية affineEncoder("zend",alphabet2,kmul=5,isAffineOrMul=True) # فتكون الكلمة بعد التشفير 'vunp' # الآن سنفك التشفير affineDencoder("vunp",alphabet2,kmul=5,isAffineOrMul=True) # 'zend' هناك العديد من المشفرات الأخرى التي يمكن استخدامها، وأشهرها Hill و Playfair و ADV و AutoKey و RC4 و Vigenère cipher إلخ.. وتختلف عن بعضها في مدى تعقيد عملية التشفير وقوته وصعوبة كسره.
  3. تحديث: بدءًا من ويندوز 11 أصبح بالإمكان فتح أي تطبيق APK (تطبيق آندرويد) على الحاسوب بدون الحاجة إلى تثبيت محاكي أو أيّة برامج أخرى.
  4. يمكنك أن تستخدم الدالة delete_cookie: resp.delete_cookie('token') هذه الدالة تمكنك أيضاً من تحديد مسار ( افتراضياً "/") من خلال الوسيط path، وكذلك مجال domain (افتراضياً يكون None): resp.delete_cookie('token', path='/', domain='domain.com')
  5. إذا كنت بحاجة إلى إزالة جميع مراجع M2M دون لمس الكائنات الأساسية، فمن الأسهل العمل من اتجاه آخر: interest.mood_set.clear() على الرغم من أن هذا لا يعالج سؤال OP بشكل مباشر، إلا أنه غالبًا ما يكون مفيدًا في هذه الحالة.
  6. استخدم: Article.__name__ نماذج Django ترث من ModelBase، حيث أنه يمثل صنف علوي "Metaclass" لجميع النماذج.
  7. الإجابة بسيطة، تتطلب منك معرفة الأساسيات فقط. سأكتب لك كافة الطرق، وأنت نظمها وأكمل حسب المطلوب: في لغة السي يمكنك إيجاد طول السلسلة بالشكل التالي: #include <stdio.h> #include <string.h> int main() { // نقوم بتعريف مصفوفة من المحارف لتخزين السلسلة الناتجة فيها char myStr[100]; // تعريف متغير سنستخدمه داخل الحلقة // القيمة النهائية لهذا المتغير ستمثل طول السلسلة أيضاً int i; // لإدخال السلسلة scanf نستخدم الدالة scanf("%s", myStr); // i نقوم بتعريف حلقة فارغة تقوم بزيادة قيمة المتغير // myStr وتتوقف عندما تجد المحرف الذي يدل على نهاية السلسلة في المصفوفة for (i = 0; myStr[i] != '\0'; ++i); // أخيراً نطبع طول السلسلة printf("Length of Str is %d", i); return 0; } لإيجاد طول سلسلة في c++ فالأمر مشابه لكن أبسط: #include <iostream> #include <string.h> using namespace std; int main() { string str = "Hi"; int i = 0; for (i = 0; str[i]; i++); cout << i << endl; return 0; } هناك دوال جاهزة أيضاً لإتمام الأمر مثل length و size، أعرف أنك لاتحتاج لطريقة جاهزة لكن سأضعها للآخرين: #include <iostream> using namespace std; int main() { string str = "C++ Programming"; // str.length() يمكنك أيضاً استخدام cout << "String Length = " << str.size(); return 0; } طريقة أخرى بأسلوب C-style من خلال استخدام الدالة strlen: #include <iostream> #include <cstring> using namespace std; int main() { char str[] = "C++ Programming"; cout << "String Length = " << strlen(str); return 0; }
  8. حاول أن تحل السؤال بنفسك ونحن نساعدك ونصحح لك، لكننا لانقوم بحل الواجبات الدراسية.
  9. بالنسبة للسؤال الأول المذكور في العنوان "ما هو المقصود بالاستثناءات Exception"؟ الاستثناء هو حدث غير مرغوب فيه أو غير متوقع، يحدث أثناء تنفيذ البرنامج أي في وقت التشغيل run time أو في وقت الترجمة compile time، مما يعطل التدفق الطبيعي لتعليمات البرنامج. ملاحظة: هناك فرق بين الخطأ Error والاستثناء، فالخطأ هو مشكلة تحدث بشكل رئيسي بسبب نقص موارد النظام lack of system resources في وقت التشغيل، ولا يمكن التقاطه أو معالجته. أمثلة على هذه الأخطاء هي OutOfMemoryError و LinkageError و AssertionError، إلخ.. وهي جميعاً تمثل صفوفاً فرعية subclasses من الصف Error. لكن يشترك الخطأ والاستثناء في أنهما صفوف فرعية من الصف Java Throwable التي تنتمي إلى حزمة java.lang. لن أدخل أكثر في تفاصيل الفروق بينهما لكي لانبتعد عن السؤال الأساسي. بالنسبة للسؤال الثاني "ما هي انواع الاستثناءات في لغة جافا"؟ فهناك نوعين من الاستثناءات: Checked Exceptions: تعني خطأ برمجي يحدث أثناء ترجمة البرنامج، وهي استثناءات يجب أن يتم التقاطها ومعالجتها من خلال كتلة catch أو من خلال جملة throws وإلا ستتسبب في إنهاء البرنامج وطباعة رسالة تتبع المكدس stack trace (تقرير عن إطارات المكدس النشطة في نقطة معينة من الوقت أثناء تنفيذ برنامج). أمثلة على هذه الاستثناءات هي SQLException و IOException و File Not Found Exception و No Such Field Exception و Interrupted Exception و No Such Method Exception و Class Not Found Exception إلخ.. مثال برمجي: public class Main { public static void main(String[] args) { int s; s = "'s' should be String"; } } رسالة الخطأ: Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - incompatible types: java.lang.String cannot be converted to int هذا الخطأ يعني أن هناك مشكلة في النوع المستخدم لتخزين البيانات. ثم أخبرنا بسبب المشكلة و هي أنه لا يمكن تحويل الـString ل int , أي لا يمكن تخزين قيمة نوعها String في متغير نوعه int. Unchecked Exception: تعني خطأ منطقي يحدث أثناء تشغيل البرنامج run time، وهذا النوع من الاستثناءات لايجب معالجته أو التقاطه أبداً، ولايقوم المترجم بالكشف عن هكذا استثناءات (أي على عكس النوع السابق)، حيث تقع على عاتق المبرمج مسؤولية التأكد من عدم حدوث هذه الأخطاء. أمثلة على هذه الاستثناءات No Such Element Exception و Undeclared Throwable Exception و Empty Stack Exception و Arithmetic Exception و Null Pointer Exception و Array Index Out of Bounds Exception و Security Exception و ArrayIndexOutOfBoundException. مثال برمجي: public class Main { public static void main(String[] args) { int[] arr = { 4, 5 }; System.out.println( arr[6] ); } } Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 6 هذا الخطأ يعني أن العنصر ليس موجود في المصفوفة، ثم أخبرنا بسبب المشكلة و هي أنه لم يجد عنصر يحمل الـ index رقم 6.
  10. يمكنك استخدام الدالة ()ord، حيث نمرر لهذه الدالة محرفاً وتُرجع لنا عدداً صحيحاً يمثل قيمة الآسكي المقابلة لهذا المحرف. مثال: ord('a') الخرج: 97 وللتحويل المعاكس (أي من عدد صحيح إلى المحرف الذي يقابله حسب ترميزالآسكي): char(97) والخرج: 'a' تحتوي الأكاديمية على العديد من المقالات عن لغة بايثون، يمكنك الاطلاع عليها من هنا.
  11. الهدف منه أنه في كل مرة يتم فيها تنفيذ الكود نحصل على نفس النتائج، لأن تقسيم الداتاسيت يكون عشوائي وبذلك تكون قدد ضمنت أن تقسيم الداتاسيت سيكون نفسه، أي بمعنى آخر، ستحصل على نفس التقسيم للداتاسيت في كل مرة تقوم بها بتنفيذ الكود. هذا الأمر مهم جداً ولاسيما في الحالات التي تريد فيها مقارنة أداء عدة خوارزميات على نفس الداتاسيت أو حتى أثناء القيام بعملية ضبط المعاملات العليا للنموذج (Hyper-Parameters)، فعلى فرض تريد تجريب أداء خوارزمية SVM و LR على هذه البيانات فمن المفترض أن يتم القياس على أساس نفس الداتاسيت ونفس التقسيم، لأن اختلاف تقسيم البيانات يؤدي إلى نتائج مختلفة. نقول أن الهدف من ذلك هو Reliability أي الموثوقية. الموثوقية في الإحصاء والقياسات النفسية هي التطابق العام للقياس. يُقال إن المقياس يتمتع بموثوقية عالية في حال نتج عنه نتائج مماثلة في ظل ظروف ثابتة.
  12. تم تمرير المُعطىs1 للوسيط s الذي يعبر عن حجم نقاط البيانات، حيث تعطى مصفوفة تحوي حجم كل نقطة، وبناءان على ذلك ستأخذ أول نقطة (1,2) حجم 100، في حين تأخذ النقطة الثانية (2,3) حجم 200 وهذا يظهر جلياً عند تنفيذك الكود حيث تكون أحجام النقط مختلفة. على الجانب الآخر c1 أعطيت ل c وهي لكي لا تأخذ كل نقطة نفس اللون أي لكي يكون لدينا ألوان مختلفة فلو كان مثلاً لدينا: c1=[1, 1, 3, 4, 5] ونفذنا الكود: import matplotlib.pyplot as plt import numpy as np x=[1,2,3,4,5] y=[2,3,1,10,12] s1=[100,200,50,400,600] c1=[1, 1, 3, 4, 5] plt.scatter(x, y, c=c1, s=s1) plt.colorbar() سوف تكون لون النقطة الأولى نفس لون النقطة الثانية لأنهما تأخذان قيمة واحدة، على عكس باقي النقاط، حيث تأخذ كل نقطة لون لأنه يوجد 3,4,5 قيم مختلفة.
  13. بالتأكيد أفضل، ولاسيما إذا كنت مبتدءاً أو متوسط الخبرة، لا داع لإعادة اختراع العجلة إذا كانت موجودة ومن مصادر موثوقة مثل Sklearn أو Orange أو Keras أو أي إطار عمل آخر. أُطر العمل هذه (المكتبات) يتم بناؤها من قبل فرق بحثية لديها خبرة طويلة في المجال وهي مُدققة ومُجربة ومُحسنة وخالية من الأخطاء. الحالة الوحيدة التي اقترح عليك فيها بناء الخوارزمية بمفردك (وأشجع على ذلك) هي في حال كنت تريد التعلم (فهم كيف تعمل هذه الخوارزميات). على سبيل المثال، في بداية تعلمي قمت ببرمجة خوازمية التصنيف اللوجستي و خوارزمية التوقع الخطي وبناء شبكات عصبونية بنوعيها (Deep&Shallow) وحتى شبكات من نوع RNN ثم بدأت أضيف لهذه الأكواد المزيد من الخصائص و المزيد من ال Optimization method، وكانت غايتي فقط التعلم. أما الآن فأنا استخدم أُطر العمل الجاهزة لإنجاز المهام، وهذا مايقوم به جميع المبرمجين، فكل مايهمك هو معرفة ماتقوم به الخورازمية وكيف تتعامل معها. الكلام المذكور أعلاه يؤكد عليه الدكتور جايسون براونلي.
  14. اعتقد أنه يمكنك القيام بذلك من خلال نهج مشابه للنهج التالي، حيث أن CUSTOM_STATIC_PATH هو متغير يتم تعريفه ضمن التكوين (configuration) الخاص بك. @app.route('/cdn/<path:filename>') def custom_static(filename): x=send_from_directory(app.config['CUSTOM_STATIC_PATH'], filename) return x وضمن القالب: {{ url_for('custom_static', filename='foo') }}
  15. يمكنك الاطلاع على التوثيق overview/#running-tests: Test discovery is based on the unittest module’s built-in test discovery. By default, this will discover tests in any file named “test*.py” under the current working directory. هذا يعني أنه يمكن أن يكون لديك ملفات مسماة مثل test_feature.py و test_api.py وسيتم اكتشاف كل هذه بواسطة ال management command. سبب اكتشاف test.py هو أنه يتطابق أيضا مع نمط test * .py.
  16. كل من notify و notifyAll هما دالاتان للكلاس thread وتستخدمان لتقديم إشعارات أو تنبيهات (notification) للخيط (thread). هناك عدة اختلافات أساسية بينهما: Notification: في حالة ال multiThreading فإن دالة notify تُرسل التنبيه (Notification) إلى خيط واحد فقط من عدة خيوط مُنتظرة (تنتظر تحرير القفل Lock). بينما notifyAll تقوم بإرساله إلى كل الخيوط التي تنتظر القفل. من ناحية الأداء: تحتاج notify إلى ذاكرة (Memory) و CPU أقل مقارنةً ب notifyAll (أي أنها أقل استهلاكاً للموارد)، والسبب في ذلك يعود إلى أنها ترسل إشعاراً إلى خيط واحد فقط على عكس notifyAll التي ترسله إلى كل الخيوط المُنتظرة. Risk factor (عامل الخطر): في notify يكون خطر فقدان التنبيه (أو الإشعار) عالي، لإن التنبيه يتم إرساله إلى خيط واحد فقط على عكس notifyAll التي ترسله إلى كل الخيوط المنتظرة وبالتالي إذا فقد أحد الخيوط التنبيه فهناك خيوط أخرى تتلقى التنبيه و يمكنها تنفيذ المطلوب. Interchangeable أو قابلية التبديل: بالنسبة ل notify فلا يوجد إلا خيط واحد فقط وبالتالي هذه الخاصية ليست موجودة، أما في notifyAll كل الخيوط المُنتظرة تكون قابلة للتبديل. Thread identification (تحديد الخيط): في حالة notify فواحد فقط من بين كل الخيوط سيستلم القفل فقط، على عكس notifyAll فمن غير الممكن تحديد أي من الخيوط سيستلم القفل (lock)، حيث أنه يتم إرسال التنبيه إلى كل الخيوط المنتظرة. مثال يعبر عن حالة استخدام: public class A { public static void main(String[] args){ B objB = new B(); objB.start(); synchronized(objB){ try{ System.out.println("Waiting.."); objB.wait(); } catch(InterruptedException e){ } System.out.println("Total: " + objB.total); } } } class B extends Thread{ int tot; public void run(){ synchronized(this){ for(int j=0; j<50 ; j++){ tot=tot+ i; } notify(); } } } الخرج: Waiting.. Total : 1148
  17. في حال كنت تتعامل مع الكلاس Thread، فيمكنك استخدام الدالة ()stop، حيث تقوم هذه الدالة بإنهاء تنفيذ الخيط (Thread) الذي قام باستدعائها. مثال: public class JavaStopExp extends Thread { public void run() { for(int i=0; i<4; i++) { try { // إيقاف الخيط لمدة 100 ميلي ثانية sleep(100); // طباعة اسم الخيط الحالي System.out.println(Thread.currentThread().getName()); }catch(InterruptedException e){System.out.println(e);} // التقاط الاستثناء في حال تم رميه System.out.println(i); } } public static void main(String args[]) { // إنشاء الخيط Ex th=new Ex (); // تشغيل الخيط th.start(); // إيقافه th.stop(); System.out.println("Thread th is stopped"); } } ملاحظات: هذه الدالة لاتُعيد أي قيمة. هذه الدالة تمتلك وسيط واحد (اختياري): public final void stop(Throwable obj) حيث أن obj يمثل الكائن القابل للرمي (Throwable) المراد رميه. هذه الدالة ترمي الاستثناء SecurityException إذا كان الخيط الحالي لايمكنه تعديل الخيط. بعد إيقاف الخيط لايمكنك إعادة تشغيله من خلال الدالة start. في حال كنت تستخدم الواجهة Runable فهنا يمكنك استخدام الدالة interrupt، كما يلي: يمكن استخدام الدالة interrupt لإيقاف أو استئناف تنفيذ الخيط من خيط آخر. على سبيل المثال، تُقاطع التعليمة التالية الخيط t1 من الخيط الحالي: t1.interrupt(); في حال كان t1 في حالة إيقاف مؤقت (sleeping)، فإن الاستدعاء السابق سيؤدي إلى رمي الاستثناء InterruptedException. وبالتالي اعتماداً على ماسنكتبه داخل الكتلة catch يمكننا إيقاف الخيط أو جعله يستمر في التنفيذ. مثال: public class Ex implements Runnable { public void run() { for (int i = 0; i <= 9; i++) { System.out.println("m" + i); try { Thread.sleep(1500); continue; } catch (InterruptedException ex) { System.out.println("continue"); } } } public static void main(String[] args) { // إنشاء الخيط Thread t1 = new Thread(new Ex()); // تشغيله t1.start(); try { // إيقاف الخيط لمدة 4000 ميلي ثانية Thread.sleep(4000); // استدعاء دالىة المقاطعة t1.interrupt(); } catch (InterruptedException ex) { //معالجة الاستثناء // لاتقم بأي شيئ } } } في المثال السابق يقوم الخيط t1 بطباعة رسالة كل 1500 ميلي ثانية، بينما خيط الدالة الرئيسية main يقوم بمقاطعته بعد 400 ميلي ثانية. يمكنك أيضاً أن تلاحظ أنه في جملة try..catch في الدالة run، يتم متابعة تنفيذ الحلقة بعد أن تتم مقاطعة النيسب، وهذا يعني أن الخيط يستمر تشغيله بينما هو في حالة الإيقاف المؤقت (sleeping). الآن لو أردنا بدلاً من ذلك أن يتم إيقاف الخيط، فكل ماعلينا فعله هو تعديل جملة try..catch في الدالة run، كما يلي: try { Thread.sleep(1500); } catch (InterruptedException ex) { System.out.println("stop"); return; // فقط return نقوم بكتابة التعليمة } حيث يؤدي جعل الدالة run تنفذ التعليمة return إلى إنهاء الخيط.
  18. يمكنك حذف الجلسة كالتالي: from flask import session session.clear() حل آخر وجدته من الخلال المرور على session واستدعاء الدالة () session.pop على كل مفتاح في ال session: for key in list(session.keys()): session.pop(key) // تقوم بحذف المتغير من الجلسة pop
  19. يمكننا القيام بذلك من خلال تحقيق الواجهة Runnable أو من خلال الكلاس Thread الموجودان في الحزمة java.lang. بعد ذلك نقوم بوضع الكود الذي نريد أن يتم تنفيذه ضمن خيط (Thread) منفصل بداخل الدالة ()run التي يتم تجاوزها من Thread/Runnable. بعد ذلك نقوم باستدعاء الدالة()start من الكائن Thread لوضع الخيط (Thread) في حالة التشغيل. مثال: في المثال التالي قمنا بتعريف الكلاس Ex1 الذي يقوم بوراثة الكلاس Thread، وبداخل هذا الكلاس قمنا بتجاوز override الدالة ()run، و وضعنا بداخلها الكود الذي نريد أن يتم تنفيذه بشكل تفرعي (أي ضمن Thread منفصل) الكود هو طباعة رسالة بسيطة تمثل اسم ال thread، حيث تقوم الدالة getName بإرجاع اسم ال Thread الحالي. بعد ذلك وضمن الدالة الرئيسية main قمنا بتعريف كائن من الكلاس Ex1، ثم استدعينا الدالة start التي ستقوم بتشغيل ال thread. وأخيراً نقوم بطباعة اسم ال Thread الحالي (وهنا يكون main thread أي Thread الدالة الرئيسية). // Thread نجعل الكلاس الحالي يرث الكلاس public class Ex1 extends Thread { // run الآن نضع الكود الذي نريده ضمن الدالة public void run() { System.out.println("name: " + getName()); } public static void main(String[] args) { // الآن ضمن الدالة الرئيسية للبرنامج نقوم بإنشاء كائن من الكلاس السابق Ex1 t1 = new Ex1(); // من خلال الكائن start ثم نستدعي الدالة t1.start(); System.out.println("name: " + Thread.currentThread().getName()); } } الخرج: name: Thread-0 name: main حيث أن Thread-0 هو اسم الخيط الذي قمنا بإنشائه و main هو اسم الخيط الذي يمثل الدالة الرئيسية (أي برنامج جافا). الآن سيتبادر لأذهاننا السؤال التالي.. متى يتم إنهاء (متى يموت) الخيط Thread-0؟ الإجابة هي عندما تنتهي الدالة run من تنفيذ كامل الكود الموجود ضمنها. أما بالنسبة للخيط main فينتهي عندما تنتهي الدالة الرئيسية main تنفيذ كامل التعليمات البرمجية التي تحتويها. ملاحظة: في المثال السابق نلاحظ أنه تم تنفيذ الخيط Thread-0 أولاً ثم تم تنفيذ الخيط main، وهذا ليس بالضرورة أن يتم دائماً، فمثلاً لو جربنا تنفيذ الكود السابق أكثر من مرة سنلاحظ أن الخرج قد يختلف (أي قد يتم تنفيذ النيسب main أولاً مثلاً)، وليس بالضرورة أن يتم تنفيذ النيسب Thread-0 أولاً دوماً، حيث أن ترتيب تنفيذ النياسب هو أمر يتم تحديده في خوارزمية الجدولة للمعالج وليس من قبل المبرمج، إلا أنه يمكننا التحايل على هذا الأمر من خلال استخدام دوال تقوم بإجبار المعالج على تنفيذ الخيط الذي نريده بالترتيب الذي نحتاجه (سنتعرف على الأمر بعد قليل). - يمكننا تحقيق نفس الأمر السابق من خلال الواجهة Runnable: public class Ex2 implements Runnable { public void run() { System.out.println("name: " + Thread.currentThread().getName()); } public static void main(String[] args) { Runnable th = new Ex2(); Thread t2 = new Thread(th); t2.start(); System.out.println("name: " + Thread.currentThread().getName()); } } الآن كيف يمكننا ترتيب تنفيذ الخيوط (أي كيف يمكننا أن نجبر المعالج على تنفيذ خيط قبل الآخر)؟ يمكننا القيام بذلك من خلال الدالة join. على سبيل المثال لو أردنا أن يتم تنفيذ الخيط Thread-0 قبل الخيط main نقوم باستدعاء الدالة join من خلال الخيط Thread-0 بداخل الخيط main: public class Ex2 implements Runnable { public void run() { System.out.println("name: " + Thread.currentThread().getName()); } public static void main(String[] args) { Runnable th = new Ex2(); Thread t2 = new Thread(th); t2.start(); t2.join(); System.out.println("name: " + Thread.currentThread().getName()); } } مثال آخر: public class ThreadJoinExample implements Runnable { public void run() { for (int i = 1; i <= 10; i++) { System.out.println("m" + i); } } public static void main(String[] args) { Thread t1 = new Thread(new ThreadJoinExample()); t1.start(); t1.join(); System.out.println(Thread.currentThread().getName()); } } سيكون الخرج: m1 m2 m3 m4 m5 m6 m7 m8 m9 m10 main ملاحظة: الدالة join ترمي الاستثناء InterruptedException لذا يجب أن يتم التقاطه (في المثال السابق تجاهلت ذلك).
  20. - التغليف هو أشبه بكبسولة الدواء التي تحتوي داخلها خليطاً من المواد الطبية. - يعتبر التغليف أحد المفاهيم الأساسية في البرمجة الشيئية (OOP). - إليك عدة تعاريف لمفهوم التغليف (Encapsulation): هو العملية التي نقوم من خلالها بتغطية الكود والبيانات مع بعضها ضمن وحدة واحدة. هو فكرة مضمونها تجميع البيانات والطرق التي تعمل على تلك البيانات في وحدة واحدة، على سبيل المثال ، Class في Java. هو عبارة عن أسلوب يمكن اتباعه لإخفاء البيانات الأساسية في الكلاس, أي لإخفاء الخصائص الموجودة فيه ( Global Variables ), و جعل الكلاسات الأخرى قادرة على التعامل مع هذه الخصائص فقط من خلال دوال يقوم بإنشائها المبرمج الأساسي للكلاس. - من الناحية العملية، فإنه في التغليف، يتم إخفاء المتغيرات أو البيانات الخاصة بالكلاس عن أي كلاء آخر ولا يمكن الوصول إليها إلا من خلال دالة عضو من نفس الكلاس. - يتم تحقيق مبدأ التغليف عن طريق التصريح عن جميع المتغيرات في الكلاس كمتغيرات خاصة (private) وكتابة طرق (دوال) عامة (public) في الكلاس لتعيين قيم المتغيرات والحصول عليها. - فوائد التغليف: من خلال توفير طريقة (دالة) setter أو getter فقط، يمكنك جعل الكلاس للقراءة فقط أو للكتابة فقط (زيادة المرونة) على سبيل المثال، إذا أردنا جعل الكلاس قابل للقراءة فقط "class read-only" نقوم بحذف دوال الضبط setter، وفي حال أردنا جعله للكتابة فقط نقوم بحذف دوال ال getter. يوفر لك التحكم في البيانات. طريقة لتحقيق إخفاء البيانات في Java. لن يكون لدى المستخدم أي فكرة عن التنفيذ الداخلي للكلاس، حيث لن يكون مرئياً للمستخدم كيف يخزن الكلاس القيم في المتغيرات. سيعرف المستخدم فقط أننا نقوم بتمرير القيم إلى طريقة الضبط setter ويتم تهيئة المتغيرات بهذه القيمة الممررة. قابلية إعادة الاستخدام: يحسن التغليف أيضاً من قابلية إعادة الاستخدام ويسهل تغييره مع المتطلبات الجديدة. مثال: سنعطي الآن مثالاً بسيطاً للتغليف، حيث سنقوم بتعريف كلاس يحقق مبدأ التغليف و يحتوي على حقل واحد فقط مع دالة setter ودالة getter. package com.javaproject; public class Student{ // private هنا قمنا بتعريف متغير يمثل اسم الطالب وحددنا الوصول إليه ك private String studentName; // هنا قمنا بتعريف متغير للحصول على هذا المتغير // getter أي أننا عرفنا دالة public String getName(){ return studentName; } // هنا قمنا بتعريف دالة لضبط قيمة هذا المتغير // أي قمنا بتعريف دالة تقوم بتحديد اسم الطالب // setter أي أننا عرفنا دالة public void setName(String studentName){ this.studentName=studentName; } } الآن سنقوم باختبار الكلاس السابق الذي قمنا بتغليفه: package com.javatproject; class Test{ public static void main(String[] args){ // إنشاء كائن من الكلاس السابق // أو بمعنى آخر تعريف طالب Student stu=new Student(); // تحديد اسم لهذا الطالب stu.setName(Ali"); // طباعة اسم هذا الطالب System.out.println(stu.getName()); } }
  21. تُستخدم هذه الكلمة في سياقات مختلفة لتصف الحالات التي يكون فيها شيء ما في عدة أشكال مختلفة. غالباً يمكننا القول أنه شكل واحد رئيسي وينبثق منه أشكال فرعية يسهل التعامل معها،على سبيل المثال بناء دالة تنفذ أوامر مختلفة على حسب الكائن الذي نمرره لها عند إستدعاءها. في العادة تعدد الأشكال يكون مربتط بشكل أساسي بالأصناف و الوراثة حيث تكون الدالة مبنية على أساس الصنف الأب، و لكننا عند إستدعاءها نمرر لها كائن من إحدى الأصناف التي ترث منه والتي تحتوي نفس الدوال لكن بتعريفات خاصة كما سنرى في المثال بعد قليل، لكن بصورة عامة فإن تعددية الأشكال مفهوم غير محصور فقط بالأصناف والوراثة وسأعطي الآن أمثلة على حالات مختلفة ومنوعة من تعددية الأشكال وبلغات برمجية مختلفة. على سبيل المثال في لغة بايثون هناك الدالة len التي تحقق مبدأ تعددية الأشكال: # len هنا قمنا بتمرير سلسلة نصية للدالة print(len("ali")) # len للدالة list بينما هنا قمنا بتمرير قائمة print(len([20, 30])) خرج البرنامج: 3 2 حيث قمنا بتمرير سلسلة نصية في البداية لهذه الدالة فأعطتنا طولها (عدد الأحرف)، ثم في المرة الثانية قمنا بتمرير قائمة، فأعطتنا عدد عناصرها، هذا مثال لتعددية الأشكال، حيث أن الدالة len تسلك سلوكاً مختلفاً بناءان على معطياتها. مثال آخر لتعددية الأشكال: def add(a, b, c = 0): return a + b+c print(add(10, 33)) print(add(20, 2, 5)) حيث قمنا بتعريف دالة add يمكنها جمع عددين أو 3 أعداد (الوسيط c يأخذ القيمة 0 بشكل افتراضي (أي في حال لم تمرر لها قيمة) وهي قيمة محايدة لعملية الجمع)، ثم قمنا باستدعاء الدالة مرتين، الأولى لجمع عددين والثانية لجمع 3 أعداد، هذا مثال آخر بسيط لتعددية الأشكال. مثال آخر لتعددية الأشكال لكن هذه المرة مع الأصناف: # تعرف صنف يمثل بلد class Syria(): def capital(self): print("Damascus") def language(self): print("Arabic") # تعريف صنف يمثل بلد آخر class England(): def capital(self): print("London") def language(self): print("English") # إنشاء كائن يمثل البلد الأول obj_sy = Syria() # إنشاء غرض ثاني يمثل البلد الثاني obj_eng = England() # obj_eng ومرة إلى الكائن obj_sy يشير مرةً إلى الكائن country الآن سنجعل متغير الحلقة # وفي كل مرة سيستدعي نفس الدوال # وهذه صورة أخرى من أشكال تعددية الأشكال for country in (obj_sy, obj_eng): country.capital() country.language() - الآن سنعطي مثالاً آخر لتعددية الأشكال لكن هذه المرة مع الوراثة ومع لغة أخرى هي الجافا، حيث أن أحد الاستخدامات الشائعة لمفهوم تعددية الأشكال يحدث عندما يكون لدينا مرجع من صف أب (نسميه مقبض)يشير إلى كائن من صف ابن. لنفرض مثلاً لدينا شاحنة ونريد نقل مجموعة سيارات بحيث كل شاحنة تتسع ل 10 سيارات ، وتنقل نوع واحد من السيارات ( يمكن تشبيه الشاحنة بمصفوفة تضم عناصر من نمط واحد ). لنفرض لدينا نوعين من السيارات نريد أن ننقلهم 4:BMW و 4:AUDI حسب الشروط المفروضة سنحتاج شاحنتين في كل واحدة سنضع 4 من نفس النوع .. الفكرة أن الشاحنة الواحدة (مصفوفة ) لا تحمل نوعين لكنها تتسع للعدد الكلي ، أي أننا قمنا بعملية نقل صحيحة لكنها مكلفة ( حجزنا شاحنة ويوجد أماكن فارغة بالأولى + ماذا لو كان لدينا أكثر من نوعين .. ) الحل : يجب أن نبحث عن شاحنة ( مصفوفة) تحمل النوعين، ونعلم أن المصفوفة لا تحمل الا نوع واحد، ما العمل؟ هنا تأتي " تعددية الأشكال" بأن نعرف صف أب للصفين السابقين وليكن Carونرث منه الصفين BMW و AUDI ونأخذ مصفوفة مقابض من Car ( نمط واحد ) وكل عنصر (مقبض) نجعله يشير الى الكائن المطلوب ( BMW أو AUDI ). وهكذا نكون قد حللنا المشكلة و خزنا كائنات من صفوف مختلفة بمصفوفة واحدة مثال : (يمكن نسخ الكود وتنفيذه لملاحظة النتائج): package javaapplication29; class Car { void type () { System.out.println("car");} } class BMW extends Car { @Override void type () { System.out.println("BMW");} } class AUDI extends Car { @Override void type () { System.out.println("AUDI");} } public class JavaApplication29 { public static void main(String[]args ){ Car[]c =new Car[8]; //نعبئ أربع سيارات BMW for( int i=0; i<4 ; ++i ) c[i] = new BMW(); //نعبئ أربع سيارات AUDI for( int i=4; i<8 ; ++i ) c[i] = new AUDI(); //تعليمة طباعة للتأكد من أنه تم تعبئة النوعين for( int i=0; i<8 ; ++i ) c[i].type(); } } مثال آخر: // الفئة الأم (الأشكال) class Shapes { public void area() { System.out.println("The formula for area of "); } } // فئة المثلثات class Triangle extends Shapes { public void area() { System.out.println("Triangle is ½ * base * height "); } } // فئة الدوائر class Circle extends Shapes { public void area() { System.out.println("Circle is 3.14 * radius * radius "); } } class Main { public static void main(String[] args) { Shapes myShape = new Shapes(); // إنشاء كائن الأشكال Shapes myTriangle = new Triangle(); // إنشاء كائن المثلثات Shapes myCircle = new Circle(); // إنشاء كائن الدوائر myShape.area(); myTriangle.area(); myShape.area(); myCircle.area(); } نلاحظ أنه في كل كائن نستعمل الدالة ()area بشكل مختلف حسب طبيعة الكائن و هذا ما يسمى ب polymorphism. - الآن سأعطي مثالاً آخر لتعددية الأشكال لكن بلغة برمجية أخرى هي لغة الأسس (مشابهة جداً للغة ال C): لتحقيق مبدأ تعددية الأشكال مع الأصناف في هذه اللغة يجب أن نقوم بتعريف الدوال كمؤشرات، وهذا يتم من خلال إضافة الكلمة المفتاحية as_ptr للأمر handler (بشكل مشابه للكلمة المفتاحية virtual في c++). فلنفترض أن لدينا الصنف التالي: class A { handler this.set(i: Int) as_ptr { ... } } في التعريف أعلاه، سيضيف المترجم إلى الصنف A مؤشراً على الدالة set. وهذا يُمكّن الكائنات المشتقة من A (التي تقوم بوراثتها) من تخصيص الدالة عبر تغيير قيمة المتغير. مثلاً: class B { @injection def a: A; handler this.set(i: Int) set_ptr { ... } } في هذا التعريف الصنف B يشتق من الصنف A ثم يغير مؤشر الدالة set (باستخدام الكلمة المفتاحية set_ptr) لتعريف خاص ب B. الآن لو كان هناك دالة تستلم سنداً أو مؤشراً على A فيمكنك إعطاؤها سنداً ل B وستراه الدالة على أنه صنف A مع دالة set خاصة ب B. قد تكون الأمور غامضة قليلاً، لكنها ستتضح في المثال التالي... قمنا بتعريف صنف اسمه Country يحوي 3 دوال لم يحدد متنها (body). بعدها قمنا بتعريف صنف اسمه Canda و صنف اسمه Syria يرثان من الصنف Country و كل منهما يحتوي تعريفاً خاصاً لنفس الدوال الموجودة في الصنف الأب Country. بعدها قمنا بإنشاء دالة اسمها printCountryInfo مهمتها استدعاء جميع الدوال الموجودة في الكائن الذي نمرره لها بشرط أن يكون هذا الكائن قد تم إنشاؤه من صنف يرث من الصنف Country، حيث أن هذه الدالة تستلم سنداً من الصنف الأب. في النهاية قمنا بإنشاء كائن من الصنف Canda و كائن من الصنف Syria و تمرير كل كائن منهما للدالة printCountryInfo. import "Srl/Console.alusus" use Srl.Console; // تعريف صنف يمثل بلد class Country { // دالة سنستخدمها لطباعة اسم البلد handler this.name() as_ptr; // دالة سنستخدمها لطباعة العاصمة handler this.capital() as_ptr; // دالة سنستخدمها لطباعة اللغة handler this.language() as_ptr; } // تعريف صنف يمثل بلد محدد هو كندا class Canda { // country سنقوم الآن بوراثة الصنف @injection def country: Country; // تعريفاً مخصصاً Country الآن سنقوم بتعريف الدوال الموجودة في الصنف handler (this:Country).name() set_ptr{ print("Country: Canda\n") } handler (this:Country).capital() set_ptr{ print("Capital: Ottawa\n") } handler (this:Country).language() set_ptr{ print("Language: English\n") } } // تعريف صنف آخر يمثل بلد محدد هو سوريا class Syria { @injection def country: Country; handler (this:Country).name() set_ptr{ print("Country: Syria\n") } handler (this:Country).capital() set_ptr{ print("Capital: Damascus\n") } handler (this:Country).language() set_ptr{ print("Language: Arabic\n") } } // Country دالة تقوم باستلام سند من الصنف // ثم في متن هذه الدالة سنقوم باستخدام السند للوصول إلى الدوال function printCountryInfo(re:ref[Country]){ re.name() // تؤدي إلى طباعة اسم بلد re.capital() // العاصمة re.language() // اللغة print("\n********************\n") } // Canda إنشاء كائن من الصنف def obj1: Canda; // لطباعة معلومات هذا البلد printCountryInfo سنقوم الآن بتمريره إلى الدالة printCountryInfo(obj1) // Syria سنكرر الآن نفس الأمر لكن مع كائن من الصنف def obj2: Syria; printCountryInfo(obj2) /* Country: Canda Capital: Ottawa Language: English ******************** Country: Syria Capital: Damascus Language: Arabic ******************** */ هكذا نكون قد كتبنا دالة بسيطة تحقق مبدأ تعددية الأشكال. مقال ذات صلة: سؤال ذات صلة:
  22. غالباً ما تكون البيانات التي ستعمل عليها أبعاد متعددة مما يجعل من الصعب عرضها بيانياً أو تخيلها. وبالتالي لايكون العدد الأمثل للمجموعات واضحاً. لكن لحسن الحظ هناك طريقة لتحديد ذلك رياضياً وهي elbow method: elbow method هي طريقة لإيجاد عدد العناقيد (ال ـClusters) في خوارزمية K-Means، أو بمعنى آخر هي طريقة لإيجاد قيمة K في خوارزمية K-Means. نقوم برسم بياني يعبر عن العلاقة بين WCSS (Within Cluster Sum of Squares) و عدد العناقيد (ـClusters)، ثم نختار عدد العناقيد number of clusters عندما يبدأ التغيير في WCSS في الاستقرار. بالنسبة ل WCSS فهي مجموع مربعات الفرق بين كل عضو في ال Cluster ومركزها. الرسم البياني يعبر عن هذا الكلام حيث أن قيم K من 1 إلى 10 ويتم حساب قيمة WCSS المقابل لكل منها، كلما زاد عدد المجموعات ، ستبدأ قيمة WCSS في الانخفاض. تكون قيمة WCSS أكبر عندما تكون K = 1. عندما نحلل الرسم البياني ، يمكننا أن نرى أن الرسم البياني سيتغير بسرعة عند نقطة ما ، وبالتالي إنشاء شكل مرفق أو كوع (Elbow). من هذه النقطة ، يبدأ الرسم البياني في التحرك بشكل موازٍ للمحور السيني تقريباً (استقرار). قيمة K المقابلة لهذه النقطة هي قيمة K المثلى أو العدد الأمثل من المجموعات: elbow method هي أفضل طريقة موجودة لإيجاد قيمة K. لاتوجد مساوئ تذكر..
  23. مقالات ذات صلة: المزيد من الجافا.. التجريد Abstract: هناك حالات نحتاج فيها أن نعرف صف يمثل فكرة مجردة بدون تعريف كامل لطرائق هذا الصف، مثلاً قد يطلب منا تعريف صفوف تمثل مركبات متعددة مثل سيارات أو طائرات أو شاحنات أو دراجات نارية. في هذه الحالة يكون الحل الأمثل هو تعريف صف يمثل فكرة مجردة وهذه الفكرة هنا هي "المركبة" فكل المركبات تشترك بأنها تتحرك ولكن حركة الطائرة تختلف عن حركة القطار مثلاً. إذاً نقوم بتعريف الصف المجرد الذي يمثل المركبة ونعرف ضمنه طريقة مجردة تعبر عن حركة المركبة، وبعدها نستطيع وراثة مركبات متعددة من هذا الصف، فمثلاً يمكننا وراثة صف يمثل قارب ونقوم بتعريف طريقة الحركة فيه على أنها حركة في الماء ونستطيع تعريف صف يمثل طائرة تكون طريقة الحركة فيه هي الحركة في السماء وهكذا.. نعرف الصف المجرد بالشكل: abstract class class_name{...} كما يجب أن تعلم أن الصفوف المجردة يمكن أن تحوي داخلها طرائق مجردة ويمكن أن لاتحوي أي طريقة مجردة، حيث أننا نقوم عن طريقة ما أنها طريقة مجردة إذا كانت بدون جسم (أي بدون كتلة تحقيق) أي لاتملك أي تعريف Implementation: abstract public void function(); #abstract لاحظ أنها بلا جسم+نضع بدايتها الكلمة أيضاً يجب أن تعلم أنه في حال كان الصف يحوي طريقة مجردة فيتوجب أن يكون هذا الصف مجرد أيضاً. والصف المجرد لايمكن أخذ كائنات منه، حيث يمكننا فقط وراثته، وعند وراثته يجب أن نقوم بتحقيق كل الطرق الموجودة فيه Implementation. abstract class vehicle{ abstract void motion(); } # نقوم بوراثته class car extends vehicle{ void motion(){ System.out.print("The car uses wheels to walk on the roads"); } } # class plane extends vehicle{ void motion(){ System.out.print("fly in the sky"); } } وأخيراً، يمكننا أن نعرف ضمن الصف المجرد باني لكن كما نعلم أن الباني لايمكن وراثته وإنما يمكننا فقط استدعاؤه من خلال الصفوف الأبناء. كما أنه لايمكن أن يكون الباني مجرداً لأنه بالأصل لاتتم وراثته. أيضاً يتوجب على الصف الذي يرث الصف المجرد (مثلاً car) أن يحقق كل الطرق المجردة في الصف المجرد (vehicle) وإلا سيكون هو مجرد أيضاً (صف مجرد يرث صف مجرد). الواجهات Interfaces : هي بنية شبيهة بالصف وشبيها جداً بال Astract Class. ويمكن أن تحتوي على ثوابت وطرق مجردة فقط. يمكن تشبيه الواجهة بصف مجرد كل طرقه مجردة. ولتعريفها: interface Interface_name{ ... } لايمكننا أخذ كائن من الواجهة، وإنما يتم تحقيق طرائقها من خلال صف يقوم بتحقيقها من خلال الكلمة المحجوزة implements عوضاً عن الكلمة extends التي تعبر عن الوراثة. (الانترفيس يتم تحيقها وليس وراثتها). interface Face{...} class A imlements Face{...} الآن الصف A يحقق الواجهة Face وبالتالي يجب أن نعرف كل طرائق الواجهة Face في الصف A. كما يمكن للصف أن يحقق أكثر من واجهة. interface i1 { } interface i2 { } class A implements i1, i2 { } يستطيع الإنترفيس أن يرث من إنترفيس أو أكثر. أي يستطيع الإنترفيس أن يفعل extends لإنترفيس أو أكثر. interface i1 { } interface i2 { } interface i3 extends i1, i2 { } يمكن للصف أن يرث صف ويحقق واجهة أو أكثر: interface i { } class A { } class B extends A implements i { } Nested Interfaces: interface i1 { interface i2 { interface i3 { } } } class A implements i1 { } //i1 يحقق الواجهة A الكلاس class B implements i1.i2 { } //i2 هنا يحقق الواجهة class C implements i1.i2.i3 { } // i3 يمكن أن تحتوي الواجهة على مايلي: دوال لا تملك body, أي Abstract Method. متغيرات مع إعطائهم قيمة بشكل مباشرةً عند تعريفهم. لأن أي متغير تقوم بتعرفه بداخل الإنترفيس يعتبر معرف كـ public final static بشكل تلقائي. Nested Classes, أي كلاس نوعه static بداخل كلاس نوعه static كما يمكن أن يحوي على Nested Interfaces أي إنترفيس بداخل إنترفيس. والإنترفيس يعتبر دوماً public. -نقاط مهمة حول الـ Abstract Class: 1. الكلاس العادي لا يمكنه أن يحتوي على دوال نوعها abstract. 2. الـ Abstract Class يمكنه أن يحتوي على دوال عادية, و يمكنه أن يحتوي على دوال نوعها abstract. 3. إذا قمت بتعريف الكلاس كـ abstract, فهذا يعني أن هذا الكلاس لا يمكن إنشاء كائنات منه. 4. بما أنه لا يمكن إنشاء كائنات من Abstract Class, فهذا يعني أنه للإستفادة من هذا الكلاس, يجب وراثته. 5. الكلاس الذي يرث من كلاس نوعه abstract, يجب أن يفعل Override لجميع الدوال المعرفة كـ abstract. -نقاط مهمة حول الـ Abstract Method: 1. إذا وضعت الكلمة abstract قبل إسم الدالة, فهذا يعني أنها دالة من النوع abstract. 2. الدالة التي نوعها abstract هي دالة لها إسم و نوع محدد, لكنها لا تحتوي على body (جسم), أي لا تملك أقواس بداية و نهاية { }. 3. الدالة العادية تحتوي على أقواس البداية و النهاية { }. 4. الـ Abstract Method يجب وضع فاصلة منقوطة ; في آخرها بدل أقواس البداية و النهاية. 5. الكلاس الذي يرث من كلاس نوعه abstract, يجب أن يقوم بإعادة تعريف (Override) لجميع الدوال التي نوعها abstract, أي يجب أن يكتب الـ body لهذه الدوال. - ملاحظات حول الواجهات: 1. لا نستخدم أي Access Modifer عند تعريف الواجهة. 2. لا نستخدم أي Access Modifer عند تعريف دالة بداخل الواجهة. 3. بداخل الواجهة جميع الدوال يجب أن لا تملك body, و يمكن جعل الدالة ترمي إستثناء. 4. لا يمكن للواجهة أن تملك دالة بانية 5. لا يمكن إنشاء كائن من واجهة. 6. لا يستطيع الكلاس أن يرث (extends) من واجهة بل يُمكنه تنفيذ (implements) واجهة أو أكثر 7. الكلاس الذي يُنفذ واجهة ما عليه إعادة تعريف جميع دوال تلك الواجهة. 8. يُمكن لواجهة أن ترث (extends) من واجهة أو أكثر.
  24. - وحدات التخزين الضوئية – ذواكر – CD: بالعودة تاريخياً فقد طورت هذه التقنية شركة فيليبس وسوني عام 1981 خلال سعيهما لإيجاد وسيلة تخزين موسيقية ذات سعة كبيرة ولها عدة أنواع : 1. CD - ROM: وهي أقراص تتألف من ثلاث طبقات : • الطبقة العليا للحماية. • طبقة وسطى تتألف من طبقة مذهبة عاكسة وأحياناً طبقة من الفضة ولكن بكفاءة أقل. • الطبقة الأساسية وتكون بقطر 120 mm وسعة تبلغ 680 MB . • وتستخدم مساراً حلزونياً واحداً ينطلق من المركز إلى المحيط و يقسم إلى قطاعات. وتتم القراءة من الداخل إلى الخارج، أي من مركز القرص إلى خارج القرص و يتم التخزين من خلال تسليط شعاع ليزري بطول موجة nm 780 ذو استطاعة عالية على طبقة من البلاستيك متعددة الكربونات فيترك أثراً عبارة عن تجويف بعرض 0.6μm . • أما القراءة فتتم من خلال تسليط شعاع ليزري ذو استطاعة منخفضة بحدود 0.5mv وعندما يصطدم بالتجويف يتبعثر الشعاع ولا ينعكس أما عند اصطدامه بالطبقة المسطحة فينعكس الشعاع من الطبقة المطلية بالذهب أو الفضة، و يتم تحسس الشعاع المنعكس بواسطة ثنائي ضوئي و يحوّل هذا الضوء إلى نبضات كهربائية تحول إلى الحاسب لمعالجته. 2. أقراص إعادة الكتابة CD – RW - ROM: تتألف من نفس الأقراص السابقة ولكنها متعددة مرات الكتابة عليها وتتم الكتابة عليها كما يلي : • تستخدم طبقة حرارية تحت الطبقة البلاستيكية تتغير طبيعتها وتترك أثراً عند تسليط ليزر بدرجة حرارة من 900 – 1300 F وعند مسح الكتابة تتم عملية الالتحام للأثر الليزري بتسليط شعاع ليزري جديد بدرجة حرارة تبلغ F 400 وهكذا ... - DVD أو DVD-ROM: هو اختصار للقرص الرقمي متعدد الاستخدامات "digital versatile disc" أو قرص الفيديو الرقمي "digital video disc"، قرصًا قادرًا على تخزين كمية كبيرة من البيانات أكثر من CDROMs. تستخدم أقراص DVD على نطاق واسع لتخزين وعرض الأفلام والبيانات الأخرى. * أحد أكثر أقراص DVD شيوعًا هو قرص أحادي الجانب أحادي الطبقة "single-sided, single-layer"، قادر على حمل 4.7 جيجا بايت. * القرص أحادي الجانب ذو الطبقة المزدوجة "single-sided, double-layer" قادر على حمل ما بين 8.5-8.7 جيجا بايت. * القرص مزدوج الوجه أحادي الطبقة "double-sided, single-layer" قادر على استيعاب 9.4 جيجا بايت. * على الرغم من ندرته ، إلا أن القرص مزدوج الطبقة ذو الوجهين "double-sided, double-layer" قادر على استيعاب ما يصل إلى 17.08 جيجابايت. بالنسبة للفرق بينهما: كلاهما أجهزة تخزين ضوئية ومن الناحية الفيزيائية متشابهين فكلاهما لهما وجه مُسمى وأخر غير مُسمى ويستخدمان الليزر، لكن أكبر فرق بين CDROMs وأقراص DVD هو سعتها. يحتوي قرص CDROM عادةً على 700 ميجابايت من البيانات لكل قرص بينما يمكن أن يحتوي قرص DVD على 4.7 جيجابايت على طبقة واحدة. إذاً يمكن أن تستوعب أقراص DVDs فيلم كامل في قرص واحد بينما لا تستطيع CDROMs ذلك. هناك ميزة أخرى لأقراص DVD وهي سرعات نقل البيانات (أسرع بكثير من CD)، حيث تُترجم السرعة الأساسية لـ CDROM التي تبلغ 1x إلى معدل نقل بيانات يبلغ 1.23 ميجابت / ثانية مع وصول محركات أقراص CDROM النموذجية إلى سرعات 56x وسرعات نقل تبلغ حوالي 68.8 ميجابت / ثانية. بينما سرعة 1x لقرص DVD لديها معدل نقل أعلى يبلغ 10.80 ميجابت / ثانية. على الرغم من أن الحد الأقصى الحالي لمحركات أقراص DVD المتاحة بشكل شائع لا يزال حوالي 20x ، إلا أنه لا يزال يترجم إلى 216 ميجابت / ثانية.
  25. اقترح عليك استخدام مكتبة textblob حيث أنها تحتوي دالة تدعى correct تستخدم من أجل هذا الغرض، انظر إلى المثال التالي: # استيراد المكتبة from textblob import TextBlob # TextBlob نقوم بتمرير الحملة إلى باني الصف tbObj = TextBlob("I amm goodd at speling mstake.") # tbObj من الكائن correct نقوم باستدعاء الدالة res = tbObj.correct() print(res) الخرج: I am good at spelling mistake. بالنسبة لمثالك وكونه لديك قائمة من الجمل ستحتاجيه لإنشاء حلقة تكرارية للمرور عليها: from textblob import TextBlob l=["Titanic is a 1997 Americn epic roance and diaster film dircted, writen, prodced, and co-edited by James Cameron.", "The Shawshank Redemption is a move produced by Niki Marvin and directed by Frank Darabont."] for sent in l: tbObj = TextBlob(sent) print(tbObj.correct()) """ Titanic is a 1997 American epic romance and disaster film directed, written, produced, and co-edited by James Cameron. The Shawshank Redemption is a move produced by Wiki Margin and directed by Rank Darabont. """
×
×
  • أضف...