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

كل الأنشطة

تحدث تلقائيًا

  1. الساعة الماضية
  2. الدالة describe تُستخدم للحصول على ملخص إحصائي سريع لبيانات DataFrame أو Series، هذه الدالة تقوم بحساب مجموعة من الإحصائيات الأساسية للبيانات مثل: عدد القيم غير الفارغة (count) المتوسط (mean) الانحراف المعياري (std) الحد الأدنى (min) الرباعي الأول (25%) الوسيط (50%) الرباعي الثالث (75%) الحد الأقصى (max) و هي دائما توفر طريقة سريعة ومفيدة للحصول على نظرة عامة حول توزيع البيانات وإحصائياتها الأساسية.
  3. اليوم
  4. السلام عليكم اي هي مفهوم الداله describe() الموجود في مكتبه pandas ؟
  5. يوجد العديد من الاستضافات المجانية و لكن عليك تحديد اللغة و اطار العمل الذي ستستخدمه في مشروعك لتعرف ماهي الاستضافة التي تناسب مشروعك . هذه بعض المواقع التي تقدم استضافات مجانية : Netlify: و هذا الموقع يدعم اطر العمل التالية React, Angular, Vue.js, Next.js, و غيرها من اطر العمل لكن هذه اشهرها Vercel: يدعم نفس أطر العمل التي يدعمها Netlify تقريبا و يوجد استضافات اخرى لكن نرجو منك تزويدنا بمعلومات عن مشروعك لنقول لك ماهي الاستضافة المناسبة.
  6. هل نحن المبرمجين الذي نتحكم في ان تكون Private او Public اذا كان الجواب نعم ادا كنت تعرف مقال يتحد تعن هذا الموضوع بار الله فيك
  7. عندي مشروع تخرج هل توجد استضافة مجانية لاتهم المدة ؟ بارك الله فيكم
  8. يمكنك إنشاء أكثر من ملف cpp في نفس المشروع، لكن المشكلة التي تواجهك سببها وجود تعريفين للدالة main في كل من p1.cpp و h.cpp. الدالة main يجب أن تكون معرفة مرة واحدة فقط في المشروع، لأنها نقطة البداية للتنفيذ، إذا كنت بحاجة إلى استخدام وظائف أو أكواد موجودة في الملفات الأخرى، فيمكنك تعريفها في ملفات cpp الأخرى بدون الدالة main. أما إذا كنت تريد استخدام ملفين يحتوي كل منهما على الدالة main، لا يمكنك ذلك في مشروع واحد، لأن المشروع الواحد يمكن أن يحتوي فقط على نقطة دخول واحدة (main). ولكن يمكنك إنشاء مشروعين منفصلين، كل مشروع يحتوي على ملف main الخاص به.
  9. اها فهمت شكرا كتير الك والله يعطيك الف عافيه
  10. تعرفت في المقالات السابقة على الدوال print()‎ و input()‎ و len()‎، وأصبحت تعرف بتوفير بايثون عدّة دوال مضمنة في اللغة built-in functions مثلها، لكنك تستطيع كتابة دوال خاصة بك أيضًا. يمكنك القول أن الدالة هي برنامج صغير داخل برنامجك، ولكي نفهم سويةً كيف تعمل الدوال فنحتاج إلى إنشاء واحدة. أدخل الشيفرة الآتية في المحرر لديك وسم الملف باسم helloFunc.py: ➊ def hello(): ➋ print('Howdy!') print('Howdy!!!') print('Hello there.') ➌ hello() hello() hello() أول سطر هو عبارة def التي تعرف دالةً باسم hello()‎، والشيفرة التي تلي عبارة def هي جسم الدالة ➋، الذي يحتوي على الشيفرة التي ستنفذ حين استدعاء call الدالة، وليس حين تعريف الدالة. الأسطر الثلاثة التي تحتوي على hello()‎ ➌ هي استدعاءات الدالة، وعملية استدعاء الدالة هي كتابة اسمها متبوعًا بقوسين، وقد تمرر إليها بعض الوسائط arguments بين القوسين. حينما يصل تنفيذ البرنامج إلى استدعاء هذه الدوال، فسينتقل التنفيذ إلى أول سطر في الدالة ويبدأ بتنفيذ الشيفرات الموجودة فيها حتى يصل إلى نهايتها، وحينها يعود التنفيذ إلى السطر البرمجي الذي استدعى الدالة، ثم يكمل البرنامج عمله كالمعتاد. ولأننا استدعينا الدالة hello()‎ ثلاث مرات، فإن الشيفرة الموجودة داخل الدالة hello()‎ ستنفذ ثلاث مرات، وحينما تشغِّل البرنامج السابق سيظهر لديك: Howdy! Howdy!!! Hello there. Howdy! Howdy!!! Hello there. Howdy! Howdy!!! Hello there. أحد الأغراض الأساسية من تعريف الدوال هو تجميع الشيفرات مع بعضها والتي يمكن أن تنفذ عدة مرات، فلو لم تكن لدينا الدالة السابقة فسنحتاج إلى نسخ ولصق الشيفرة عدة مرات كما يلي: print('Howdy!') print('Howdy!!!') print('Hello there.') print('Howdy!') print('Howdy!!!') print('Hello there.') print('Howdy!') print('Howdy!!!') print('Hello there.') هنالك قاعدة عامة تقول أن عليك تفادي تكرار الشيفرات نفسها قدر الإمكان، لأنك إذا قررت مستقبلًا أن تجري تغييرًا عليها -كأنك وجدت علّة وحللتها مثلًا- فعليك أن تجري هذا التغيير في كل مكان نسخت إليه تلك الدالة. وكلما زادت خبرتك البرمجة وجدتَ نفسك تقلل من تكرار الشيفرات، مما يجعل برامجك أقصر وأسهل للقراءة وأسهل في التعديل والتحديث. عبارة def مع معاملات تذكر حينما كنت تستدعي الدالة print()‎ أو len()‎ كنت تمرر إليها قيمًا تسمى بالوسائط arguments، وذلك بكتابتها بين القوسين. يمكنك أيضًا أن تعرف دوالك التي تقبل وسائط، وجرب هذا المثال في ملف باسم helloFunc2.py: ➊ def hello(name): ➋ print('Hello, ' + name) ➌ hello('Alice') hello('Bob') ستبدو المخرجات كما يلي حين تشغيل البرنامج السابق: Hello, Alice Hello, Bob لاحظ أن تعريفنا للدالة hello()‎ في هذا المثال يحتوي على معامل باسم name ➊. المعاملات parameters هي المتغيرات التي تحتوي على قيمة الوسائط arguments. أي حينما نستدعي دالةً مع وسائط arguments فإن قيمة تلك الوسائط ستكون مخزنة في المعاملات parameters. حين استدعاء الدالة hello()‎ لأول مرة سنمرر إليها القيمة 'Alice' ➌ وسينتقل التنفيذ إلى داخل الدالة، وستُضبَط قيمة المعامل name إلى القيمة 'Alice' تلقائيًا، ومن ثم ستطبع هذه القيمة باستخدام الدالة print()‎ ➋. أحد الأمور التي من المهم تذكرها حول المعاملات هي أن القيمة المخزنة فيها ستنسى حين إنتهاء تنفيذ الدالة، فلو كتبت print(name)‎ بعد استدعاء hello('Bob')‎ في البرنامج السابق، فسيظهر لك الخطأ NameError لعدم وجود متغير باسم name، وذلك لأن برنامجنا سيحذف المتغير name بعد إنتهاء استدعاء الدالة hello('Bob')‎ ولذا سنشير في print(name)‎‎ إلى المتغير name الذي لن يكون موجودًا. هذا يشبه كثيرًا كيف تحذف قيمة المتغيرات في برامجنا السابقة من الذاكرة حين انتهاء تنفيذها. وسنتحدث عن سبب حدوث ذلك تفصيلًا لاحقًا في هذا المقال حينما نتتحدث عن النطاق المحلي local scope. التعريف والاستدعاء والتمرير والوسائط والمعاملات! كثرت علينا المصطلحات الجديدة كالتعريف define والاستدعاء call والتمرير pass والوسائط arguments والمعاملات parameters. لننظر سويةً إلى الشيفرة الآتية لمراجعتها: ➊ def sayHello(name): print('Hello, ' + name) ➋ sayHello('Abdullatif') تعريف الدالة يعني إنشاءها، وكما في عبارة الإسناد spam = 42 التي تنشِئ المتغير spam سنستعمل العبارة def لتعريف الدالة sayHello()‎ ➊. السطر الذي فيه sayHello('Abdullatif')‎ ➋ يستدعي الدالة التي أنشأناها، مما ينقل تنفيذ البرنامج إلى بداية الشيفرة الموجودة داخل الدالة، وسطر الاستدعاء السابق يمرر السلسلة النصية 'Abdullatif' إلى الدالة، والقيمة التي تمرر إلى الدالة تسمى وسيطًا، وسيُسند الوسيط 'Abdullatif' إلى المتغير المحلي المسمى name، وتسمى المتغيرات التي تحمل قيمة الوسائط الممررة إلى الدالة بالمعاملات. من السهل الخلط بين المصطلحات السابقة، لكن حاول أن تستوعبها جيدًا لكي تفهم بقية المقال بسهولة. القيم المعادة وعبارة return عندما تستدعي الدالة len()‎ وتمرر إليها وسيطًا مثل 'Hello' فستكون القيمة الناتجة من الدالة هي الرقم 5، الذي يمثل طول السلسلة النصية التي مررتها إليها. يمكننا القول عمومًا أن الناتج إحدى الدوال يسمى بالقيمة المعادة return value من تلك الدالة. حينما تنشِئ دالةً باستخدام العبارة def فيمكنك أن تحدد ما هي القيمة المعادة من الدالة باستخدام العبارة return. تتألف عبارة return من: الكلمة المحجوزة return قيمة أو تعبير برمجي يجب أن تعيدها الدالة حين استخدام تعبير برمجي مع عبارة return فستكون القيمة المعادة هي ناتج ذاك التعبير. فمثلًا البرنامج الآتي يعرف دالةً تعيد سلسلةً نصيةً مختلفةً اعتمادًا على الرقم المُمرَّر إليها كوسيط. احفظ الشيفرة الآتية في ملف باسم magic8Ball.py: ➊ import random ➋ def getAnswer(answerNumber): ➌ if answerNumber == 1: return 'It is certain' elif answerNumber == 2: return 'It is decidedly so' elif answerNumber == 3: return 'Yes' elif answerNumber == 4: return 'Reply hazy try again' elif answerNumber == 5: return 'Ask again later' elif answerNumber == 6: return 'Concentrate and ask again' elif answerNumber == 7: return 'My reply is no' elif answerNumber == 8: return 'Outlook not so good' elif answerNumber == 9: return 'Very doubtful' ➍ r = random.randint(1, 9) ➎ fortune = getAnswer(r) ➏ print(fortune) حين يبدأ تنفيذ البرنامج السابق فستسورد بايثون الوحدة random ➊، ثم ستعرف الدالة getAnswer()‎ ➋، ولأننا عرفنا الدالة ولم نستدعها فلن تنفذ الشيفرة الموجودة داخلها، بل سينتقل التنفيذ مباشرةً إلى استدعاء الدالة random.randint()‎ التي مررنا إليها وسيطين هما 1 و 9 ➍ وسيعاد منها عدد عشوائي بين 1 و 9 (بما في ذلك الرقمين 1 و 9) وتخزن هذه القيمة في المتغير r. تستدعى الدالة getAnswer()‎ مع تمرير الوسيط r ➎، وينتقل التنفيذ إلى بداية الدالة getAnswer()‎ ➌، وستخزن قيمة الوسيط r في المعامل answerNumber، ثم اعتمادًا على القيمة الموجودة في answerNumber فستعيد الدالة إحدى السلاسل النصية المعرفة مسبقًا، ومن ثم سيعود التنفيذ إلى النقطة التي استدعيت فيها الدالة getAnswer()‎ ➎ وستسند السلسلة النصية المعادة إلى المتغير ذي الاسم fortune، الذي سيمرر بدوره إلى الدالة print()‎ ➏ ويطبع على الشاشة. لاحظ أنك تستطيع تمرير القيم المعادة من الدوال كوسيط مباشرةً إلى دوال أخرى، لذا يمكنك أن تختصر الأسطر الثلاثة الآتية: r = random.randint(1, 9) fortune = getAnswer(r) print(fortune) إلى السطر المكافئ: print(getAnswer(random.randint(1, 9))) تذكر أن التعابير البرمجية تتألف من قيم وعوامل، ويمكن استخدام استدعاءات الدوال في تعبير برمجي لأن الاستدعاء سيؤول إلى قيمة معادة من تلك الدالة. القيمة None هنالك قيمة في بايثون تسمى None وهي تمثل عدم وجود قيمة. والقيمة None هي القيمة الوحيدة لنوع البيانات NoneType، وقد تسمي لغات البرمجة الأخرى هذه القيمة بالاسم null أو nil أو undefined. وكما في القيم المنطقية True و False فيجب أن نكتب None بحرف N كبير. يمكن أن تفيد هذه القيمة-التي-ليس-لها-قيمة حين الحاجة إلى استعمال قيمة لا تمثل شيئًا، فإحدى استخدامات None مثلًا هي القيمة المعادة من الدالة print()‎ التي تطبع نصًا على الشاشة، لكنها لا تعيد أي قيمة على عكس دوال أخرى مثل len()‎ أو input()‎، ولأن من المفترض أن يكون هنالك قيمة ناتجة لجميع استدعاءات الدوال في بايثون فاستدعاء print()‎ سيعيد القيمة None. لنجرب السطرين الآتيين في الصدفة التفاعلية لنرى ذلك: >>> spam = print('Hello!') Hello! >>> None == spam True تضيف بايثون العبارة return None وراء الكواليس لأي دالة لا يكون لها عبارة return محددة، وهذا ما يشبه كيف تحتوي حلقات التكرار while و for على عبارة continue ضمنية في نهايتها. ستعاد القيمة None أيضًا إن استخدام عبارة return دون قيمة، أي كتبت الكلمة المفتاحية return كما هي. وسطاء الكلمات المفتاحية والدالة print()‎ تعرف أغلبية الوسائط بموضعها حين استدعاء الدالة، فمثلًا الاستدعاء random.randint(1, 10)‎ مختلف عن الاستدعاء random.randint(10, 1)‎، فحينما نستدعي الدالة random.randint(1, 10)‎ فستعيد لنا رقمًا صحيحًا بين 1 و 10 لأن أول وسيط هو الحد الأدنى من المجال والوسيط الثاني هو الحد الأقصى، بينما يسبب استدعاء random.randint(10, 1)‎ خطأً. لكن بدلًا من تعريف قيم الوسائط عبر موضعها، يمكن أن تعرف وسطاء الكلمات المفتاحية keyword arguments بوضع كلمة مفتاحية قبلها حين استدعاء الدالة، وتستخدم وسطاء الكلمات المفتاحية عادةً للمعاملات الاختيارية optional parameters. فمثلًا تمتلك الدالة print()‎ معاملين اختياريين هما end و sep لضبط ما الذي سيطبع بعد نهاية طبع الوسائط الممررة إليها وما الذي سيطبع بين تلك الوسائط على التوالي. إذا شغلنا برنامجًا يحتوي على الشيفرة الآتية: print('Hello') print('World') فسيكون الناتج كما يلي: Hello World لاحظ أن السلسلتين النصيتين المطبوعتين مفصولتان بسطر وذلك لأن الدالة print()‎ تضيف تلقائيًا محرف السطر الجديد newline character في نهاية السلسلة النصية التي تمرر إليها كوسيط. إلا أننا نستطيع ضبط قيمة الوسيط end لتغيير محرف السطر الجديد إلى سلسلة نصية مختلفة، فمثلًا إذا كتبت الشيفرة الآتية: print('Hello', end='') print('World') فسيكون الناتج: HelloWorld سيطبع الناتج في سطر وحيد لعدم وجود محرف السطر الجديد بعد السلسلة النصية 'Hello' لأننا مررنا سلسلة نصية فارغة، وهذا ما يفيدك إن أردت تعطيل الإضافة التلقائية للسطر الجديد في نهاية كل استدعاء للدالة print()‎. إذا مررت عدة سلاسل نصية إلى الدالة print()‎ فستفصل الدالة بينها تلقائيًا بفراغ واحد. جرب إدخال السطر الآتي في الصدفة التفاعلية: >>> print('cats', 'dogs', 'mice') cats dogs mice يمكنك تبديل السلسلة النصية التي تفصل بين الوسائط التي ستطبع باستخدام الوسيط sep وتمرير سلسلة نصية مختلفة إليه، جرّب ذلك في الصدفة التفاعلية: >>> print('cats', 'dogs', 'mice', sep=',') cats,dogs,mice يمكنك إضافة وسائط مفتاحية في الدوال التي تكتبها أيضًا، لكن عليك أن تتعلم أولًا عن القوائم list والقواميس dictionary التي سنشرحها في مقالات لاحقة. لكن كل ما عليك معرفته الآن هو أن بعض الدوال لها معاملات اختيارية ويكون لها مفاتيح يمكن الوصول إليها لضبط قيمتها حين استدعاء الدالة. مكدس الاستدعاء Call Stack تخيل أنك تدردش مع أحد أصدقائك، فستتحدث عن صديقك محمد، ثم تتذكر قصة عن زميلك في العمل عبد الحميد، ثم تتذكر شيئًا عن ابن عمك جميل، وحينما تنتهي قصتك عن جميل تعود إلى حديثك عن عبد الحميد، ثم تعود وتتحدث عن محمد، وبعد ذلك تتذكر أخاك بشر، وتقص قصة عن بشر، ثم تعود وتكمل القصة الأصلية لمحمد. تتبع محادثتك بنيةً شبيهةً بالمكدس stack، كما في الشكل الموالي، التي يكون فيها الموضوع الحالي في أعلى المكدس. مكدس القصص في دردشتك. وكما في محادثتك السابقة، عملية استدعاء دالة لا تؤدي إلى نقل التنفيذ إلى بداية الدالة التي جرى استدعاؤها، بل تتذكر بايثون ما هو السطر الذي استدعى تلك الدالة لكي تستطيع توفير القيمة المعادة من تلك الدالة إليه. وإذا استدعت تلك الدالة دوالًا أخرى فستعاد القيم الناتجة عن تلك الدوال إلى أماكن استدعائها الأصلية أولًا. لنفهم ما يحدث بالتفصيل سنجرب المثال الآتي بعد حفظه في ملف باسم abcdCallStack.py: def a(): print('a() starts') ➊ b() ➋ d() print('a() returns') def b(): print('b() starts') ➌ c() print('b() returns') def c(): ➍ print('c() starts') print('c() returns') def d(): print('d() starts') print('d() returns') ➎ a() سينتج البرنامج ما يلي حين تشغيله: a() starts b() starts c() starts c() returns b() returns d() starts d() returns a() returns أعرف أن الفقرة الآتية متداخلة، لكن حاول أن تركز معي فيها: حين استدعاء a()‎ ➎ فستستدعي b()‎ ➊ التي بدورها ستستدعي c()‎ ➌. والدالة c()‎ لا تستدعي غيرها بل تعرض العبارة c() starts ➍ و c() returns قبل أن يعود التنفيذ إلى السطر الذي استدعاها في b()‎ ➌. بعد أن يعود التنفيذ إلى الشيفرة في b()‎ التي استدعت c()‎ فستنتهي الدالة b()‎ وتطبع b() returns ثم يعود التنفيذ إلى السطر الذي استدعى b()‎ في a()‎ ➊. سيستمر التنفيذ في الدالة a()‎ وستستدعى الدالة d()‎، والتي تشبه الدالة c()‎ في كونها لا تستدعي دالةً غيرها بل تطبع d()‎ starts و d() returns قبل أن تعود إلى السطر الذي استدعاها في a()‎ ثم سيكمل التنفيذ من هناك، وسيطبع آخر سطر من a()‎ العبارة a()‎ returns قبل أن ينتهي تنفيذ الدالة a()‎ ونصل إلى نهاية البرنامج. مكدس الاستدعاء call stack هو الآلية التي تستعملها بايثون لتذكر أين سيعود التنفيذ بعد انتهاء تنفيذ استدعاء كل دالة. لا يخزن مكدس الاستدعاء في متغير في برنامجك وإنما تتولى بايثون أمره خلف الكواليس. فحينما يستدعي برنامجك دالةً فستنشِئ بايثون كائن إطار frame object فوق مكدس الاستدعاء، وتخزن كائنات الإطار frame objects رقم السطر الذي استدعى الدالة لكي تعرف بايثون أين يجب أن تعيد القيمة الناتجة من ذاك الاستدعاء. إذا استدعيت دالة أخرى فستضع بايثون كائن إطار آخر في المكدس فوق السابق. بعد إعادة استدعاء الدالة فستحذف بايثون كائن الإطار من أعلى المكدس وتكمل التنفيذ من السطر المخزن في ذاك الكائن. لاحظ أن كائنات الإطار تضاف وتحذف من أعلى المكدس وليس من أي مكان آخر. يوضح الشكل الموالي حالة مكدس الاستدعاء في البرنامج abcdCallStack.py حين استدعاء والعودة من كل دالة: كائنات الإطار لمكدس الاستدعاء في كل مرحلة من مراحل تنفيذ البرنامج abcdCallStack.py. يمثل أعلى مكدس الاستدعاء الدالة التي يجري تنفيذها حاليًا، وحينما يكون المكدس فارغًا فسيكون التنفيذ في متن البرنامج وخارج جميع الدوال. لا حاجة إلى تعلم المزيد حول مكدس الاستدعاء لكي تكتب برامجك، لأنه يدخل في تفاصيل تقنية عميقة لا داعي لها حاليًا. من الكافي أن تفهم أن الدوال ستعيد القيم إلى السطر الذي استدعيت فيه؛ لكني آثرت شرح مكدس الاستدعاء هنا لأن فهمه سيسهل استيعاب مفاهيم المجالات العامة والمحلية التي سنشرحها في القسم الآتي. المجالات العامة والمحلية تكون المعاملات parameters والمتغيرات الموجودة داخل إحدى الدوال ضمن مجال محلي local scope. أما المتغيرات التي تسند قيمتها خارج جميع الدوال تكون موجودة في المجال العام global scope. وبالتالي يسمى المتغير الموجود في مجال محلي بالمتغير المحلي local variable، بينما يسمى المتغير الموجود في المجال العام بالمتغير العام global variable؛ ويجب أن يكون المتغير عامًا أو محليًا، ولا يمكنه أن يكون كلاهما معًا. يمكنك تخيل المجالات scopes على أنها حاوية للمتغيرات؛ فحينما ينتهي وجود أحد المجالات المحلية فستحذف جميع المتغيرات الموجودة فيه. لاحظ وجود مجال عام وحيد الذي سينُشَأ حينما يبدأ تنفيذ برنامجك وينتهي بإنتهاء تنفيذه. يمكنك التأكد من حذف المتغيرات في المجال العام بعد إنتهاء تنفيذ البرنامج بتجربة الوصول إلى المتغيرات من برنامج آخر. يُنشَأ المجال المحلي في كل مرة تستدعى فيها إحدى الدوال. فتكون جميع المتغيرات المسندة ضمن الدالة موجودة في المجال المحلي. وحين إعادة قيمة return من الدالة فسينتهي وجود المجال المحلي وستحذف قيمة تلك المتغيرات؛ ولن يتذكر برنامج قيمة المتغيرات المخزنة من الاستدعاء السابق للدالة. تخزن المتغيرات المحلية أيضًا في كانئات الإطار frame objects في مكدس الاستدعاء call stack. يهمنا معرفة المجال المستخدم لعدة أسباب: لا يمكن للشيفرات الموجودة في المجال العام أن تستعمل أي متغيرات محلية لكن يمكن للشيفرات في المجال المحلي الوصول إلى المتغيرات العامة الشيفرة في المجال المحلي لإحدى الدوال لا تستطيع استخدام أي متغيرات موجودة في المجال المحلي لدالة أخرى يمكنك استخدام الاسم نفسه لمتغيرات مختلفة على أن تكون موجودة في مجالات مختلفة. أي يمكن أن يسمى متغير محلي بالاسم spam مثلًا ويكون هنالك متغير عام بالاسم spam أيضًا. السبب في امتلاك بايثون لمجالات مختلفة بدل من جعل جميع المتغيرات عامة هو أن بعض المتغيرات تعدل من شيفرة معينة ضمن دالة ما، وتتفاعل هذه الدالة مع بقية البرنامج عبر المعاملات parameters الممررة إليها وعبر القيمة المعادة منها؛ وهذا ما يقلل عدد الأسطر البرمجية التي تتعامل مع متغير ما وتسبب مشكلة برمجية، فإذا كان يحتوي برنامجك على متغيرات عامة فقط وحصل خطأ بسبب ضبط أحد المتغيرات إلى قيمة خطأ فسيصعب كثيرًا تتبع المشكلة في برنامجك، فقد يكون عدد الأسطر البرمجية بالمئات أو الآلاف التي قد تستطيع تعديل قيمة هذا المتغير؛ أما لو كانت العلة البرمجية بسبب قيمة خطأ لمتغير محلي فستعرف تحديدًا ما هي الأسطر البرمجية المسؤولة عن ضبط تلك القيمة وستحل المشكلة بسهولة وسرعة. لا مشكلة في استخدام المتغيرات العامة في البرامج القصيرة سهولتها، لكنها من غير المستحسن الاعتماد على المتغيرات العامة حينما تكبر برامجك. لا يمكن استخدام المتغيرات المحلية في المجال العام أمعن النظر في البرنامج الآتي الذي سيتسبب بخطأ حين محاولة تشغيله: def spam(): ➊ eggs = 31337 spam() print(eggs) إذا جربت هذا البرنامج فسيبدو الناتج كما يلي: Traceback (most recent call last): File "C:/test1.py", line 4, in <module> print(eggs) NameError: name 'eggs' is not defined سيحدث الخطأ بسبب وجود المتغير eggs داخل المجال المحلي المنشأ من الدالة spam()‎ ➊. فبعد انتهاء تنفيذ الدالة spam فسيحذف المجال المحلي ولن يبقى هنالك أي متغير باسم eggs، وحينما يحاول البرنامج تشغيل السطر print(eggs)‎ فستعطيك بايثون خطأً تقول فيه أن المتغير eggs غير معرف، وهذا منطقي إذا فكرت مليًا بالأمر؛ فحينما يكون تنفيذ البرنامج في المجال العام فلا توجد أي مجالات محلية ولن تكون هنالك أي متغيرات محلية، وبالتالي لا يمكننا استخدام سوى المتغيرات العامة في المجال العام. لا يمكن استخدام المتغيرات المحلية في مجالات محلية أخرى ينشأ مجال محلي جديد في كل مرة تستدعى فيها إحدى الدوال، بما في ذلك حين استدعاء دالة ضمن دالة أخرى. انظر إلى المثال الآتي: def spam(): ➊ eggs = 99 ➋ olive() ➌ print(eggs) def olive(): steak = 101 ➍ eggs = 0 ➎ spam() حينما يبدأ تشغيل البرنامج فستستدعى الدالة spam()‎ ➎ وسينشأ مجال محلي، وسيضبط المتغير المحلي eggs ➊ إلى 99، ثم ستستدعى الدالة olive()‎ ➋، ثم سينشأ مجال محلي جديد؛ فمن الممكن أن تكون عدة مجالات محلية موجودة جنبًا إلى جنب. وسنضبط قيمة المتغير المحلي Steak إلى 101، وسننشِئ المتغير المحلي eggs -المختلف كليًا عن المتغير الذي يحمل نفس الاسم في المجال المحلي للدالة spam()‎- ونضبط قيمته إلى 0 ➍. حين إعادة الدالة olive()‎ فسيحذف المجال المحلي المنشأ بسبب استدعائها، بما في ذلك المتغير eggs الخاص بها. وسيكمل تنفيذ البرنامج في الدالة spam()‎ ليطبع لنا قيمة المتغير eggs ➌؛ ولأن المجال المحلي الخاص بالدالة spam()‎ ما يزال موجودًا فستكون قيمة eggs هي 99 كما ضبطناها سابقًا في ذلك المجال. خلاصة الكلام السابق كله هو أن المتغيرات المحلية الموجودة في إحدى الدوال مفصولة تمامًا عن المتغيرات المحلية في دالة أخرى. يمكن قراءة المتغيرات العامة من مجال محلي أمعن النظر في المثال الآتي: def spam(): print(eggs) eggs = 42 spam() print(eggs) حينما حاولنا طباعة المتغير eggs ضمن الدالة spam()‎ بحثت بايثون عن متغير أو معامل باسم eggs في الدالة spam()‎ لكنها لم تجد، فحينها ستعدّه إشارةً إلى المتغير العام eggs، ولهذا سيطبع البرنامج السابق القيمة 42 حين تنفيذه. المتغيرات المحلية والعامة التي تحمل الاسم نفسه من المقبول تمامًا من الناحية التقنية في بايثون استخدام نفس الاسم لمتغير في المجال العام وآخر في المجال المحلي؛ لكن لتسهيل مقروئية الشيفرة فحاول تجنب فعل ذلك. لترى ما سيحدث فجرب الشيفرة الآتية: def spam(): ➊ eggs = 'spam local' print(eggs) # 'spam local' def olive(): ➋ eggs = 'olive local' print(eggs) # 'olive local' spam() print(eggs) # 'olive local' ➌ eggs = 'global' olive() print(eggs) # 'global' سيظهر الناتج الآتي حينما تجرب تشغيل البرنامج السابق: olive local spam local olive local global هنالك ثلاثة متغيرات مختلفة في البرنامج، لكنها كلها مسماة eggs، وهي كما يلي: ➊ متغير باسم eggs موجود في المجال المحلي للدالة spam()‎. ➋ متغير باسم eggs موجود في المجال المحلي للدالة olive()‎. ➌ متغير باسم eggs موجود في المجال العام. ولأن هذه المتغيرات المختلفة لها نفس الاسم فسيكون من العسير تتبع أيها يستعمل الآن؛ لذا تجنب استخدام نفس الاسم لأكثر من متغير. العبارة البرمجية global إذا أردت تعديل قيمة متغير عام ضمن دالة، فعليك استخدام العبارة البرمجية global. فإذا كان لديك سطر يشبه global eggs في بداية إحدى الدوال فهذا سيخبر بايثون أن «المتغير eggs في هذه الدالة يشير إلى متغير عام، ولا حاجة إلى إ،شاء متغير محلي بهذا الاسم». فمثلًا جرب الشيفرة الآتية: def spam(): ➊ global eggs ➋ eggs = 'spam' eggs = 'global' spam() print(eggs) استدعاء الدالة print()‎ سيؤدي إلى إظهار الناتج الآتي: spam ولأننا صرحنا أن المتغير eggs هو عام global في بداية الدالة spam()‎ ➊، فحينما نضبط eggs إلى 'spam' ➋ فستجرى عملية الإسناد إلى المتغير eggs العام، ولن ينشأ أي متغير محلي. هنالك أربع قواعد لمعرفة إن كان المتغير في المجال المحلي أم العام: إذا كان المتغير مستخدمًا في المجال العام، أي خارج جميع الدوال، فسيكون متغيرًا عامًا دومًا. إذا كانت هنالك عبارة global في إحدى الدوال، فسيكون المتغير عامًا في تلك الدالة. خلاف ذلك إذا استخدم المتغير في عبارة الإسناد داخل دالة ما، فسيكون متغيرًا محليًا. لكن إن لم يستخدم ذاك المتغير في عبارة إسناد داخل الدالة فسيكون متغيرًا عامًا. لتأخذ فكرة أفضل عن هذه القواعد فاكتب البرنامج الآتي في محرر الشيفرات واحفظه وجربه: def spam(): ➊ global eggs eggs = 'spam' # this is the global def olive(): ➋ eggs = 'olive' # this is a local def Steak(): ➌ print(eggs) # this is the global eggs = 42 # this is the global spam() print(eggs) سيكون المتغير eggs في الدالة spam()‎ عامًا لوجود العبارة global في بداية الدالة ➊، وسيكون المتغير eggs محليًا في الدالة olive()‎ لاستعماله في عبارة إسناد في تلك الدالة ➋، وسيكون eggs عامًا في steak()‎ ➌ لعدم استخدامه في عبارة إسناد أو العبارة global. إذا شغلت البرنامج السابق فستكون النتيجة هي: spam كقاعدة عامة: سيكون المتغير في دالةٍ ما إما عامًا أو محليًا، ولا يمكن استخدام متغير محلي في دالة باسم eggs ثم استخدام متغير عام بنفس الاسم لاحقًا في الدالة ذاتها. إذا حاولت استخدام متغير محلي ضمن دالة قبل أن تسند قيمةً له كما في البرنامج الآتي، فستظهر لك رسالة خطأ: def spam(): print(eggs) # ERROR! ➊ eggs = 'spam local' ➋ eggs = 'global' spam() ستظهر رسالة الخطأ الآتية إذا حاولت تجربة البرنامج السابق: Traceback (most recent call last): File "C:/sameNameError.py", line 6, in <module> spam() File "C:/sameNameError.py", line 2, in spam print(eggs) # ERROR! UnboundLocalError: local variable 'eggs' referenced before assignment يظهر الخطأ لأن بايثون سترى عبارة إسناد للمتغير eggs ضمن الدالة spam()‎ ➊ وبالتالي ستعد المتغير على أنه محلي، لكننا نحاول طباعة قيمة eggs قبل إسناد أي قيمة له، أي أن المتغير المحلي eggs غير موجود، فسيظهر الخطأ ولن تستعمل بايثون المتغير العام eggs ➋. تعامل مع الدوال على أنها «صناديق سوداء» عادةً كل ما تحتاج إليه لاستخدام دالة هو معرفة ما هي المدخلات (أي ما هي المعاملات التي تأخذها) وما هي المخرجات؛ فلا حاجة إلى أن تثقل على نفسك بمعرفة كيف تعمل شيفرة تلك الدالة. فحاول أن تنظر إلى الدوال نظرة شاملة عالية المستوى، وبإمكانك معاملتها على أنها «صندوق أسود». هذه الفكرة أساسية في البرمجة الحديثة، وسترى عدة وحدات في المقالات اللاحقة من هذه السلسلة فيها دوال مكتوبة من مبرمجين آخرين، وصحيح أنك تستطيع النظر إلى الشيفرة المصدرية لها لكن لا حاجة إلى أن تفهم كيف تعمل لكي تستعملها؛ ولأن من المستحسن كتابة الدوال دون أن تتعامل مع المتغيرات العامة فلا تقلق حول تفاعل الدوال مع المتغيرات الموجودة في المجال العام لبرنامجك. التعامل مع الاستثناءات حينما يحدث خطأ -أو بتعبير أدق «استثناء» exception- في برنامجك فهذا يعني توقف عملية التنفيذ كلها. ولا تريد أن يحدث ذلك عمليًا في البرامج الحقيقية، وإنما تريد أن يحس برنامجك بوجود الأخطاء ويتعامل معها ثم يكمل تنفيذه بسلام. فالبرنامج الآتي يتسبب بخطأ القسمة على صفر. جربه: def spam(divideBy): return 42 / divideBy print(spam(2)) print(spam(12)) print(spam(0)) print(spam(1)) عرفنا الدالة spam()‎ ومررنا إليها وسيطًا بقيم مختلفة وطبعنا قيمة قسمة العدد 42 على القيمة الممررة. هذا هو ناتج تنفيذ الشيفرة السابقة: 21.0 3.5 Traceback (most recent call last): File "C:/zeroDivide.py", line 6, in <module> print(spam(0)) File "C:/zeroDivide.py", line 2, in spam return 42 / divideBy ZeroDivisionError: division by zero يظهر الاستثناء ZeroDivisionError حينما نقسم عددًا على صفر. ويظهر لنا رقم السطر الذي يسبب هذا الاستثناء، وستعرف منه أن العبارة return في الدالة spam()‎ هي من تسبب الخطأ. يمكن التعامل مع الاستثناءات باستخدام العبارتين try و except. إذ نضع الشيفرة التي قد تسبب خطأ أو استثناءً ضمن قسم العبارة try، وسينتقل تنفيذ البرنامج إلى بداية القسم الذي يلي العبارة except في حال حدوث استثناء. يمكنك وضع الشيفرة التي قد تسبب بخطأ القسمة على الصفر ضمن كتلة try واستخدام كتلة except للتعامل مع حدوث الخطأ: def spam(divideBy): try: return 42 / divideBy except ZeroDivisionError: print('Error: Invalid argument.') print(spam(2)) print(spam(12)) print(spam(0)) print(spam(1)) حينما تتسبب الشيفرة الموجودة ضمن try باستثناء، فسينتقل تنفيذ البرنامج مباشرةً إلى الشيفرة الموجودة في except، وبعد تنفيذ تلك الشيفرة فسيكمل تنفيذ البرنامج بشكل طبيعي. ستكون نتيجة تنفيذ الشيفرة السابقة هي: 21.0 3.5 Error: Invalid argument. None 42.0 لاحظ أن أية أخطاء تحدث أثناء استدعاءات الدوال ضمن كتلة try فستعالج أيضًا. جرب البرنامج الآتي التي يستدعي الدالة spam()‎ ضمن كتلة try: def spam(divideBy): return 42 / divideBy try: print(spam(2)) print(spam(12)) print(spam(0)) print(spam(1)) except ZeroDivisionError: print('Error: Invalid argument.') سيكون الناتج كما يلي: 21.0 3.5 Error: Invalid argument. سبب عدم تنفيذ print(spam(1))‎ هو انتقال التنفيذ إلى الشيفرة الموجودة في كتلة except مباشرةً، ولن تعود لإكمال بقية كتلة try، بل ستكمل تنفيذ بقية البرنامج كالمعتاد. برنامج قصير لرسم زكزاك لنستعمل المفاهيم البرمجية التي تعلمناها حتى الآن لإنشاء برنامج حركي بسيط. سينشِئ هذا البرنامج شكل زكزاك إلى أن يوقفه المستخدم بالضغط على زر Stop في محرر Mu أو بالضغط على Ctrl+C. سيبدو ناتج البرنامج بعد تنفيذه كما يلي: ******** ******** ******** ******** ******** ******** ******** ******** ******** اكتب الشيفرة الآتية واحفظها في ملف باسم zigzag.py: import time, sys indent = 0 # كم فراغًا نضع كمسافة بادئة indentIncreasing = True # هل ستزيد المسافة البادئة أم لا try: while True: # حلقة تكرار البرنامج الأساسية print(' ' * indent, end='') print('********') time.sleep(0.1) # توقف لعُشر ثانية if indentIncreasing: # زيادة المسافة البادئة indent = indent + 1 if indent == 20: # تغيير الاتجاه indentIncreasing = False else: # إنقاص عدد الفراغات indent = indent - 1 if indent == 0: # تغيير الاتجاه indentIncreasing = True except KeyboardInterrupt: sys.exit() لننظر إلى الشيفرة سطرًا بسطر بدءًا من الأعلى. import time, sys indent = 0 # كم فراغًا نضع كمسافة بادئة indentIncreasing = True # هل ستزيد المسافة البادئة أم لا في البداية علينا أن نستورد الوحدتين time و sys، وسيستخدم برنامجنا متغيرين اثنين: المتغير indent الذي يتتبع كم فراغًا يجب أن نضع كمسافة بادئة قبل النجوم الثمانية، و indentIncreasing الذي يحتوي على قيمة منطقية بوليانية لتحدد إذا كانت المسافة البادئة ستزيد أم تنقص. try: while True: # حلقة تكرار البرنامج الأساسية print(' ' * indent, end='') print('********') time.sleep(0.1) # توقف لعُشر ثانية ثم وضعنا بقية البرنامج داخل عبارة try؛ فحينما يضغط المستخدم على Ctrl+C أثناء تشغيل برنامج بايثون فستطلق الاستثناء KeyboardInterrupt، وإذا لم تكن هنالك عبارة try-except لمعالجة الاستثناء فسينهار البرنامج وتظهر رسالة خطأ قبيحة. لتفادي ذلك سنعالج الاستثناء KeyboardInterrupt بأنفسنا باستدعاء الدالة sys.exit()‎ (هذه الشيفرة موجودة بعد نهاية كتلة try). حلقة التكرار اللانهائية while True:‎ ستكرر التعليمات الموجودة في برنامجنا للأبد، واستخدمنا التعبير ‎' ' * indent‎ لطباعة العدد الصحيح من المسافات البادئة، لكننا لا نريد أن ننتقل إلى سطر جديد بعد تلك الفراغات فنمرر الوسيط end=''‎ إلى الدالة print()‎. الاستدعاء الثاني للدالة print()‎ سيطبع لنا 8 نجوم. لم نشرح الدالة time.sleep()‎ بعد، لكن يكفي القول أنها توقف تشغيل البرنامج مؤقتًا لعُشر ثانية 0.1. if indentIncreasing: # زيادة المسافة البادئة indent = indent + 1 if indent == 20: # تغيير الاتجاه indentIncreasing = False ثم سنعدل مقدار المسافات البادئة للمرة القادمة التي تنفذ فيها حلقة while. فإذا كان indentIncreasing هو True فسنضيف واحد إلى indent. لكن حينما تصل المسافة البادئة إلى 20 فنرغب بتقليل المسافة البادئة: else: # إنقاص عدد الفراغات indent = indent - 1 if indent == 0: # تغيير الاتجاه indentIncreasing = True أما إذا كانت indentIncreasing هي False فسننقص واحد من المتغير indent، وحينما تصل قيمته إلى 0 فسنحتاج إلى زيادة المسافات البادئة مجددًا، وفي كلتا الحالتين سيعود تنفيذ البرنامج إلى بداية حلقة التكرار لطباعة النجوم مجددًا. except KeyboardInterrupt: sys.exit() إذا ضغط المستخدم على Ctrl+C في أي مرحلة من مراحل تنفيذ حلقة التكرار الموجودة داخل كتلة try فسيطلق الاستثناء KeyboardInterrrupt ثم يعالج في عبارة except، سيستمر تنفيذ البرنامج داخل كتلة expect الذي سيشغل الدالة sys.exit()‎ لإنهاء البرنامج. وعلى الرغم من أن حلقة التكرار لانهائية، لكننا نوفر طريقة آمنة لإنهاء تشغيل التطبيق من المستخدم. الخلاصة الداوال هي طريقة أساسية لتجزئة شيفراتك إلى مجموعات، ولأن المتغيرات داخل الدوال تكون في مجال محلي خاص بها فلا تؤثر الشيفرات الموجودة في إحدى الدوال على الأخرى، وبالتالي تقل الشيفرات المسؤولة عن تغيير قيمة أحد المتغيرات وبالتالي تسهل عملية تنقيح البرنامج ومعرفة الأخطاء. الدوال هي أداة رائعة لتنظيم شيفراتك، ويمكنك أن تفكر فيها على أنها صناديق سوداء: فهي تقبل المدخلات على شكل معاملات وتخرج النتائج على شكل قيم معادة، والشيفرات داخلها لا تؤثر على بقية الدوال. تعلمنا استخدام العبارتين try و except التي تتولى معالجة الاستثناءات، فكان حدوث أي خطأ في البرنامج سيؤدي إلى انهياره كما رأينا في المقالات السابقة، لكن بتعلمنا لمعالجة الاستثناءات أصبح بإمكاننا بناء تطبيقات تتعامل مع الأخطاء الشائعة دون مشاكل. والآن بعد أن تعلمت الدوال في هذا المقال، ما رأيك أن تجرب ما تعلمته في التطبيق العملي الموالي؟ وطبعًا، لا تنسَ مشاركتنا نتائج تطبيقك في التعليقات: اكتب دالةً باسم collatz()‎ التي تقبل معاملًا واحدًا اسمه number، إذا كان number زوجيًا فستطبع الدالة number // 2 ثم تعيد تلك القيمة، وإذا كان العدد number فرديًا فستطبع وتعيد ناتج 3 * number + 1. ثم اكتب برنامجًا يسمح للمستخدم بإدخال رقم صحيح واستمر باستدعاء الدالة collatz()‎ على ذاك الرقم حتى تعيد الدالة القيمة 1. (ستعمل هذه الدالة لجميع الأعداد الصحيحة، وستكون النتيجة دومًا 1! لا يعرف علماء الرياضيات تحديدًا لماذا، لكن برنامجك هو تطبيق عملي على معضلة كولاتز، حتى أن بعضهم يطلق عليها «أبسط معضلة رياضية مستحيلة»). تذكر أن تحول القيمة المعادة من input()‎ إلى رقم صحيح عبر الدالة int()‎، وإلا فستعدها بايثون على أنها سلسلة نصية. تلميحة: يكون العدد number زوجيًا إذا كان باقي القسمة على 2 هو 0 أي number % 2 == 0 وفرديًا إذا كان number % 2 == 1. يجب أن يبدو شكل تنفيذ البرنامج كما يلي: Enter number: 3 10 5 16 8 4 2 1 ترجمة -وبتصرف- للفصل Functions من كتاب Automate the boring stuff with Python لصاحبه Al Sweigart. اقرأ أيضًا المقال السابق: بنى التحكم في لغة بايثون Python أنواع البيانات والعمليات الأساسية في لغة بايثون تعلم لغة بايثون النسخة العربية الكاملة لكتاب البرمجة بلغة بايثون
  11. قمت بانشاء console application بلغة ++C فى ملف بعنوان source file عند اضافة ملف باسم p1.cpp بها بعض الاكواد وعملت run اشتغلت و عند اضافتى لصفحة اخرى باسم h.cpp بها بعض الاكواد لم تعمل وظهر error p1.obj : error LNK2005: main already defined in h-12.obj >E:\programs\Programming Advice\sources\repos\ConsoleApplication1\x64\Debug\p1.exe : fatal error LNK1169: one or more multiply defined symbols found هل ينفع اقوم بانشاء اكثر من ملف cpp فى نفس ال
  12. ربما استخدمت let أو const في تعريف اسم المتغير، فلهما نطاق كتلة block scope أي أنهما يكونان مرئيين فقط داخل الكتلة التي تم تعريفهما فيها. بينما تعريف متغير باستخدام var خارج أي كتلة كود { } يتم اعتباره متغيرًا عالميًا global، بمعنى يمكن الوصول إليه من أي مكان في الكود (سواء داخل دوال أو خارجها) ويصبح جزءًا من كائن window في المتصفحات window.name والمشكلة أنه يوجد خاصية باسم name في الكائن العالمي window ولم يعد يتم دعمها في المتصفحات حاليًا. على العكس بتعريف متغير باستخدام const أو let في النطاق العالمي، فإنه لا يصبح جزءًا من كائن window، ويتم تعريفه في نطاق الكتلة block scope الخاص بالوحدة النمطية module scope أو النص البرمجي script scope.
  13. افهمت عليك بس اسؤال ليش قبل يومين كان يتعامل مع name على انها اسم var بدون مشاكل وهسى صار لازم اختار اسم ثاني
  14. تفهمت ما تقصد، المشكلة في استخدامك لاسم المتغير name حيث يتم الخلط بينه وبين خاصية name في الكائن العالمي window ما يسبب طباعة التكرار على الأسماء في المصفوفة بالشكل التالي : Y a r o b , K h a l e d , O m e r لذا لو قمت بتغيير اسم المتغير إلى names مثلاً سيتم حل المشكلة ويتم طباعة yes أو قم باستخدام const بدلاً من var <body> <div style="text-align: center;"> <input class="input-btn" type="text"> <button class="submit-btn">submit</button> <h3 class="result-one"></h3> <h3 class="result-two"></h3> </div> </body> <script> var names = ["Yarob", "Khaled", "Omer"] document.getElementsByClassName("result-one")[0].innerHTML = names document.getElementsByClassName("submit-btn")[0].addEventListener("click", function(){ var school = document.getElementsByClassName("input-btn")[0].value for(var student of names){ console.log(student) if(student === school){ document.getElementsByClassName("result-two")[0].innerHTML = `${school} yas` break } document.getElementsByClassName("result-two")[0].innerHTML = `${school} no` } }) </script>
  15. على الفاضي جربت دخلتهم على body بس ضلت نفس المشكلة
  16. الكود الذي ارفقته لك يعمل بشكل سليم، لم ألحظ في الصورة الأولى لديك أنك كتبت كود جافاسكريبت خارج وسم body فعليك كتابة جافاسكريبت في عنصر script ونضعه في body أو head
  17. لاحظ أن وسم <script> عندك موجود بعد علامة إغلاق </body>، وهذا شيء خاطئ. المتصفح لا يقوم بتشغيل أي شيء خارج <body>. لذلك، يرجى إدخال <script> في المكان المناسب: <body> <!-- ....محتوى الصفحة --> <script> // ...محتوى السكربت </script> </body>
  18. صديقي على الفاضي هي فيديو توضيحي واذا انتبهت لما اغير اسم var من name لاي اسم ثاني وما اغير document الخاص في بضل محتوى var ظاهر على المتصف حتى لو عملت ctrl+s لل vs code وعملت ctrl +r للمتصفح WhatsApp Video 2024-05-29 at 5.24.55 PM.mp4
  19. الكود يعمل بدون مشكلة ما الخطأ الذي يظهر لك ؟ غالبًا أنت نسيت حفظ الكود عليك الضغط على CTRL + S ثم إعادة تحديث الصفحة في المتصفح. <body> <div style="text-align: center;"> <input class="input-btn" type="text"> <button class="submit-btn">submit</button> <h3 class="result-one"></h3> <h3 class="result-two"></h3> </div> <script> var name = ["Yarob", "Khaled", "Omer"] document.getElementsByClassName("result-one")[0].innerHTML = name document.getElementsByClassName("submit-btn")[0].addEventListener("click", function(){ var school = document.getElementsByClassName("input-btn")[0].value for(var student of name){ if(student == school){ document.getElementsByClassName("result-two")[0].innerHTML = `${school} yas` break } document.getElementsByClassName("result-two")[0].innerHTML = `${school} no` } }) </script> </body>
  20. انا شغال على java script بس لما اجي اعرف متغير باسم name ما بقبل تنفيذ الكود قصدي ما بشتغل صح مع انو كان قبل يشتغل بدون مشاكل شو المشكلة هي صورة لتوضيح وحتى لما احول المتغير name لتعليق بضل ظاهر على المتصفح مع العلم معمل تحديث بس على الفاضي
  21. يجب وجود collection في قاعدة البيانات لحفظ رقم الهاتف وكود التأكيد وحالة التأكيد أي الحقول كالتالي: phone لتخزين رقم هاتف المستخدم ويجب أن يكون الحقل فريدًا لكل مستخدم. verificationCode لتخزين رمز التحقق الذي يتم إرساله إلى المستخدم عبر SMS. verified لتحديد هل رقم الهاتف قد تم التحقق منه أم لا، وتستطيع جعل الحقل عبارة عن قيمة منطقية (true أو false). ثم ستحتاج إلى منطق خاص لتنفيذ ذلك، من خلال إنشاء api وليكن /send-code لإرسال كود التحقق لرقم الهاتف ولديك خدمات مثل Twilio و auth0 و Firebase لفعل ذلك. بالطبع ستقوم بحفظ الـ OTP أو الكود في قاعدة البيانات لكي تتمكن من التحقق منه، وهناك طرق مختلفة لتوليده أحدها توليده باستخدام دالة random كالتالي: const verificationCode = Math.floor(100000 + Math.random() * 900000).toString(); للتوضيح إليك مثال باستخدام Twilio: app.post('/send-code', async (req, res) => { const { phone } = req.body; const verificationCode = Math.floor(100000 + Math.random() * 900000).toString(); let user = await User.findOne({ phone }); if (!user) { user = new User({ phone, verificationCode, verified: false }); } else { user.verificationCode = verificationCode; } await user.save(); client.messages.create({ body: `Your verification code is ${verificationCode}`, to: phone, from: 'رقمك على Twilio ', }).then((message) => { console.log(message.sid); res.send('Verification code sent.'); }).catch((error) => { console.error(error); res.status(500).send('Failed to send verification code.'); }); }); بعد إرسال الكود لرقم الهاتف سيقوم هو بإدخاله عليك إذن إنشاء api آخر باسم /verify-code لاستقبال الطلب ومعالجته والتأكد من صحة الرقم. app.post('/verify-code', async (req, res) => { const { phone, code } = req.body; const user = await User.findOne({ phone, verificationCode: code }); if (!user) { return res.status(400).send('Invalid verification code.'); } user.verified = true; await user.save(); res.send('Phone number verified successfully.'); });
  22. الامر بسيط إذا كنت قد قمت بإنشاء ال Data Structuser الخاصة بقاعدة البيانات ولم ترد أن تقوم بتعديل ال collection الخاصة بالمستخدم فيمكنك إنشاء collection جديد ولنفرض إسمه sms_verifications و يحوي فقط ثلاثة حقول الأول هو ال id الخاص بالمستخدم و الثانى هو كود التفعيل المرسل و الأخير هو وقت إنتهاء الكود حيث يجب عليك وضعك وقت بحد أقصى 10 دقائق لإنتهاء الكود وذلك حفاظا على الأمان. والآن بمجرد طلب المستخدم كود تفعيل تقوم بإنشاء كود عشوائى وتقوم بحفظه في collection ال sms_verifications مع حفظ ال id الخاص بالمستخدم و من ثم إرسال الكود إلى الهاتف ويوجد العديد من المواقع التى تساعدك على ذلك مثل twilio و vonage . والآن عند إرسال المستخدم الكود الذى أرسل له تقوم باحضار السجل من sms_verifications بال id الخاص بالمستخدم ومن ثم مقارنة الكود مع التأكد من عدم إنتهاء الكود ويفضل لو قمت بعمل hash للكود وعدم حفظه كما هو فى قاعدة البيانات . وإذا كان الكود صحيح ولم تنتهى صلاحيته تقوم بوضع حالة المستخدم أنه verified
  23. الفكرة بشكل عام سهلة و يمكنك فهمها بسهولة و تطبيقها حيث بعد إنشاء الهيكلية اللازمة في MongoDB، تأكد من أن لديك مجموعة (Collection) في MongoDB لتخزين معلومات المستخدمين، بما في ذلك رقم الهاتف ورمز التحققو لنفرض على أنها بالشكل التالي: { "_id": "unique_user_id", "phone_number": "1234567890", "verification_code": "123456", "is_verified": false } عند تسجيل المستخدم أو عند طلب التحقق، قم بإنشاء رمز تحقق عشوائي وإرساله إلى رقم الهاتف باستخدام خدمة إرسال الرسائل النصية (مثل Twilio)، ثم قم بحفظ رمز التحقق المرسل في سجل المستخدم في MongoDB مع رقم الهاتف، و عندما يقوم المستخدم بإدخال رمز التحقق، قم بمقارنة الرمز المدخل مع الرمز المخزن في قاعدة البيانات، إذا كان رمز التحقق صحيحا، قم بتحديث حقل is_verified ليصبح true في سجل المستخدم.
  24. لدي سؤال الان لو اردت عمل مصادقه للرقم الهاتف ما هي الطريقه الافضل لعمل ذلك مستعملا MongoDB بعد انشاء كامل Data Structure?
  25. v22.1.0 ثبتها Globel من ثم public function show(Request $request) { return Pdf::html('<h1>Hello world!!</h1>')->save('/some/directory/invoice.pdf'); } } لما اذهب الة رابط يظهر خطأ The command "node "C:\laragon\www\moit-companies\vendor\spatie\browsershot\src/../bin/browser.cjs" "{""url"":""file:\/\/C:\\Users\\THEENG~1\\AppData\\Local\\Temp\\1165450316-0119395001716967715\\index.html"",""action"":""pdf"",""options"":{""path"":""\/so
  26. هل الخطأ السابق موجود أم ظهر خطأ أخر ؟ من المفترض أن تعمل على إصدار node 7.6.0 فما فوق . ما هو الإصدار الذى لديك ؟
  1. عرض المزيد
×
×
  • أضف...