فهم نواة Jupyter وترتيب تنفيذ خلايا Notebook

خلايا Notebook ترسل الكود إلى نواة Python، مع رمز يوضّح إعادة تشغيل النواة.

لماذا يظل Notebook يعرض نتيجة قديمة، أو يتوقف بخطأ بعد إعادة تشغيل النواة؟ تحتفظ نواة Jupyter بالمتغيرات التي أنشأتها الخلايا المنفّذة. لذلك تعتمد نتيجة الخلية على الكود الذي تنفّذه وعلى حالة الذاكرة لحظة التنفيذ.

يجمع Notebook خلايا الكود والنصوص والمخرجات في مستند واحد. ستتعرّف إلى دور Python، .venv وipykernel في تنفيذ الخلايا، ثم تميّز بين الملف المحفوظ وذاكرة النواة والنتائج المعروضة. تستخدم الأمثلة أدوات مكتبة Python فقط لفهم اعتماد الخلايا بعضها على بعض والتحقّق من الحسابات بعد إعادة التشغيل.

قبل أن تبدأ

إذا لم تتمكّن بعد من تشغيل أول Notebook، راجع دليل تثبيت Python وإعداد Jupyter في VS Code. ولمراجعة الإسناد، sum() أو القوائم، اقرأ أساسيات Python. يكمّل شرح قابلية التغيير والنسخ هذا الموضوع، لكن الآلية هنا تشمل أيضًا عددًا بسيطًا حُسب مسبقًا.

Python و.venv وipykernel: كيف تعمل نواة Jupyter؟

عندما يطلب منك VS Code اختيار نواة، يعرض غالبًا اسم بيئة مع إصدار Python. لفهم هذا الاختيار، تتبّع العلاقة بين المستند الذي تفتحه، الأدوات المثبّتة على القرص والبرنامج الذي ينفّذ خلاياك.

Python: اللغة والبرنامج الذي ينفّذها

Python لغة برمجة تتيح لك قواعدها كتابة تعليمات مثل الإسناد والحساب. ولتنفيذ هذه التعليمات، يستخدم الحاسوب برنامجًا يُسمّى Python interpreter. يوضّح دليل Python الرسمي لاستخدام Python interpreter طريقة تشغيله.

الحزمة مجموعة مكوّنات برمجية يمكنك تثبيتها لإضافة وظائف. وقد يضم الحاسوب أكثر من Python interpreter، مع مجموعات مختلفة من الحزم. لذلك تحتاج إلى معرفة أيّ Python interpreter يُشغّل نواة Jupyter التي تنفّذ خلاياك.

.venv: بيئة Python الخاصة بالمشروع

توفّر البيئة الافتراضية برنامج Python interpreter والحزم المثبّتة للمشروع، مع عزلها افتراضيًا عن حزم البيئات الأخرى. داخل مجلد projet-ia، توجد هذه البيئة في مجلد فرعي اسمه .venv. وهي الأدوات التي جهّزتها للمشروع، وتبقى على القرص حتى عندما تغلق Notebook.

يتشابه الاسمان، لكن لكل منهما معنى محدّد: venv اسم وحدة في Python تُستخدم لإنشاء البيئات الافتراضية، أما .venv فهو اسم مجلد شائع بالاتفاق، ويمكن اختيار اسم آخر له. تشرح وثائق Python للبيئات الافتراضية هذا التنظيم.

ipykernel: إتاحة التواصل بين Python وJupyter

ipykernel حزمة Python توفّر نواة Jupyter المرجعية لتنفيذ Python، وهي مبنية على IPython. تستقبل طلبات التنفيذ من الواجهة، وتتيح تنفيذ الكود باستخدام Python interpreter الخاص بالبيئة المختارة، ثم تعيد المخرجات أو الأخطاء. وتستخدم إضافة Jupyter في VS Code هذا التبادل لعرض النتائج تحت الخلايا.

لاستخدام Python الموجود في .venv كنواة، يجب أن تكون ipykernel متاحة داخل هذه البيئة. لا يكفي تثبيتها في بيئة Python أخرى. تشرح وثائق IPython للنوى وبيئات Python هذه العلاقة.

النواة: process لتنفيذ كود Python

يشير مصطلح process هنا إلى نسخة من برنامج قيد التشغيل، لها ذاكرتها الخاصة. في المثال الذي ندرسه، تعمل نواة Jupyter في process مستقل لبرنامج Python، باستخدام ipykernel من البيئة المختارة. توفّر البيئة برنامج Python والحزم المثبّتة، وتستخدمها النواة لتنفيذ الكود والاحتفاظ بالمتغيرات التي تنشئها خلاياك. يوضّح تعريف النوى في وثائق Jupyter أنها تعمل بصورة مستقلة عن واجهاتها.

عندما تعرّف خلية المتغير heures_etude، يصبح متاحًا في ذاكرة النواة النشطة، ولا يُحفظ كملف جديد داخل .venv. عند إعادة تشغيل النواة، تبدأ بذاكرة جديدة، بينما يبقى مجلد البيئة وحزمها على القرص. تحتاج بعدها إلى إعادة تنفيذ الخلايا التي تعرّف متغيراتك.

يرسل VS Code الكود إلى نواة Python ويتلقى النتائج. يوفّر مجلد .venv برنامج Python وحزمة ipykernel، وتحتفظ النواة بالمتغيرات في ذاكرتها.
على القرص، توفّر .venv برنامج Python وحزم المشروع. أثناء تشغيلها، تستخدم النواة Python وipykernel: تستقبل الكود من VS Code، تحتفظ بالمتغيرات وتعيد النتائج.

من الضغط على زر التنفيذ إلى ظهور النتيجة

  1. تختار بيئة المشروع من محدّد النواة في Notebook. يستطيع VS Code عندها استخدام Python الخاص بهذه البيئة لتشغيل النواة بواسطة ipykernel.
  2. تنفّذ خلية، فترسل الواجهة كودها إلى النواة النشطة.
  3. ينفّذ Python التعليمات باستخدام حزم البيئة والمتغيرات الموجودة مسبقًا في ذاكرة النواة.
  4. تعيد نواة Jupyter المخرجات أو رسالة الخطأ، ويعرضها VS Code تحت الخلية.
  5. تبقى النواة قيد التشغيل لتنفّذ الخلايا التالية، وتحتفظ بالمتغيرات في ذاكرتها.

اختيار النواة المناسبة في VS Code

افتح محدّد النواة أعلى Notebook من الجهة اليمنى. إذا لم تجد البيئة المطلوبة ضمن الخيارات الأخيرة، اختر Select Another Kernel…، ثم Python Environments، وحدّد .venv الخاصة بالمشروع. يشرح دليل VS Code لاختيار النواة هذه الخيارات.

قد يعرض المحدّد بيئة لم تُثبّت فيها ipykernel بعد. إذا أبلغك VS Code بنقص الحزمة، جهّز تلك البيئة بالرجوع إلى دليل تثبيت Python وJupyter. لإضافة Jupyter في VS Code وحزمة Python المسماة ipykernel دوران متكاملان: تضيف الأولى دعم Notebook إلى المحرّر، وتتيح الثانية تشغيل نواة Python لتنفيذ الخلايا.

تذكّر هذه الأدوار: يحتوي Notebook على خلاياك، وتوفّر .venv أدوات المشروع، وتتيح ipykernel التواصل مع Jupyter، بينما تنفّذ النواة الكود وتحتفظ بالمتغيرات في ذاكرتها.

نواة Jupyter: التمييز بين الملف والذاكرة

Notebook هو المستند المحفوظ على القرص، أما نواة Jupyter فتنفّذ كوده وتحتفظ بالمتغيرات في ذاكرتها. يميّز الجدول بين محتويات الملف، الواجهة التي تعرضها وحالة النواة.

العنصرالدورما الذي تتحقّق منه؟
ملف .ipynbيحتفظ بالخلايا، بياناتها الوصفية والمخرجات التي تحفظها.قد تكون المخرجات المعروضة ناتجة عن تنفيذ سابق.
محرّر VS Codeيعرض المستند ويرسل طلبات التنفيذ.ترتيب الخلايا في الصفحة لا يفرض ترتيب الضغط على أزرار التنفيذ.
نواة Pythonتنفّذ التعليمات وتحتفظ بالكائنات في ذاكرتها.قد يوجد متغير في الذاكرة رغم أن تعريفه لم يعد ظاهرًا في الملف.
ثلاثة عناصر تحتاج إلى التمييز بينها أثناء العمل في VS Code.
يحفظ ملف .ipynb الخلايا والمخرجات، بينما تحتفظ نواة Jupyter بالقائمة 23، 19، 24 والمجموع 66 في الذاكرة حتى إعادة تشغيلها.
يحفظ الملف الخلايا والمخرجات المحفوظة، وتحتفظ النواة بالمتغيرات في ذاكرتها. تُهيَّأ ذاكرة النواة من جديد عند إعادة تشغيلها.

يمكن لملفَّي Notebook استخدام البيئة نفسها .venv والأدوات نفسها، مع تشغيل نواة Jupyter مستقلة لكل منهما. عندئذ لا تتاح المتغيرات المنشأة في أحدهما داخل الآخر، لأن لكل نواة ذاكرتها الخاصة.

ماذا يحدث عندما تعيد فتح Notebook؟

لنفترض أنك حفظت Notebook بعد الحصول على 66، ثم أعدت فتحه مع نواة جديدة. قد يبقى العدد ظاهرًا تحت الخلية لأنه جزء من المخرجات المحفوظة. لكن يجب تعريف heures_etude وtotal_heures مجددًا قبل استخدامهما.

تُظهر المخرجات المحفوظة نتيجة تنفيذ سابق. ولإعادة إنتاج الحساب، تحتاج إلى تنفيذ الكود مجددًا مع الموارد اللازمة. عند مشاركة Notebook، احتفظ بالمخرجات المفيدة للقراءة وحدّد الملفات والحزم اللازمة لتنفيذه. تصف وثائق صيغة Notebook الرسمية ما يحفظه الملف.

تنفيذ الخلايا بحسب اعتمادها بعضها على بعض

تعتمد خلية على أخرى عندما تستخدم قيمة يجب أن تنتجها الخلية الأخرى. لا يكفي أن يظهر التعريف في موضع سابق من المستند، بل يجب تنفيذ الخلية التي تنشئ القيمة.

القيم 23، 19 و24 مأخوذة من الصفوف الثلاثة الأولى للعمود Hours_Studied في StudentPerformanceFactors.xlsx، من ورقة Données. المصدر: Student Performance Factors على Kaggle. كُتبت هذه القيم مباشرة في الخلايا، لذلك لا تحتاج إلى نقل ملف Excel أو تثبيت مكتبة لقراءته في هذا التمرين.

حمّل Notebook والتمرين مع حله بصيغة ZIP. فكّ ضغطه داخل projet-ia، وافتح NoyauJupyter.ipynb في VS Code، ثم اختر نواة .venv. يحتوي الملف على الكود والمخرجات نفسيهما المعروضين في الأمثلة التالية.

# Identify the Python version running this notebook.
import sys
print("Python version:", sys.version.split()[0])
Python version: 3.14.8
# Use the three verified Hours_Studied values.
heures_etude = [23, 19, 24]
print("Hours:", heures_etude)
Hours: [23, 19, 24]
# Calculate the total from the current list.
total_heures = sum(heures_etude)
# Display the value stored in the kernel.
print("Total:", total_heures)
Total: 66

تنشئ خلية البيانات القائمة heures_etude، وتحسب خلية الحساب مجموعها وتُسنده إلى total_heures، ثم تعرض خلية العرض العدد: 23 + 19 + 24 = 66.

العدد بين المعقوفين هو عدّاد التنفيذ. يشير إلى ترتيب آخر تنفيذ للخلية منذ بدء تشغيل النواة التي نفّذتها، ويمكن حفظه مع المخرجات في الملف. تساعد العدّادات غير المرتّبة على اكتشاف تنفيذ يختلف عن ترتيب القراءة، لكن تزايدها وحده لا يضمن أن النتائج محدّثة.

ماذا يحدث إذا نفّذت خلية قبل أوانها؟

لنسمِّ خلية إنشاء القائمة A، وخلية حساب المجموع B، وخلية عرضه C. تستخدم B القائمة التي أنشأتها A، ثم تستخدم C المجموع الذي حسبته B. تشير هذه الأحرف إلى مراحل الشكل، وهي مستقلة عن عدّادات التنفيذ.

تنشئ A القائمة 23، 19، 24، وتحسب B المجموع 66، ثم تعرضه C. في نواة جديدة، يسبب تنفيذ C وحدها خطأ NameError لأن total_heures غير معرّف.
تنشئ A القائمة، وتحسب B المجموع، ثم تعرضه C. في نواة جديدة، يسبب تنفيذ C وحدها خطأ لأن total_heures لم يُعرّف بعد.

الحالة الأولى: تنفيذ C قبل خلية الحساب B

أعد تشغيل النواة، ثم نفّذ C وحدها، أي خلية العرض. لا تنفّذ A أو B في هذه التجربة. يحاول Python قراءة total_heures، لكن هذا الاسم غير معرّف في النواة التي أعدت تشغيلها.

# Display the value stored in the kernel.
print("Total:", total_heures)
NameError: name 'total_heures' is not defined

يعني NameError هنا أن total_heures غير معرّف. تنفّذ نواة Jupyter الخلية المطلوبة، ولا تشغّل B تلقائيًا للحصول على المجموع الناقص.

الحالة الثانية: تنفيذ B قبل خلية البيانات A

أعد تشغيل النواة مرة أخرى، ثم نفّذ B وحدها. يحتاج الحساب هذه المرة إلى القائمة heures_etude التي لم تنشئها A بعد.

# Calculate the total from the current list.
total_heures = sum(heures_etude)
NameError: name 'heures_etude' is not defined

يتعلّق الخطأ الآن بالاسم heures_etude. من دون هذه القائمة لا يستطيع Python حساب المجموع، فلا يحدث الإسناد إلى total_heures. وسيسبب تنفيذ C بعدها خطأ أيضًا، لأن المجموع ما زال غير معرّف.

الحالة الثالثة: تنفيذ A، ثم B، ثم C

ابدأ بنواة Jupyter جديدة، ثم نفّذ A، B وC. تنشئ A القائمة [23, 19, 24]، وتحسب B القيمة 66 وتحفظها، ثم تعرض C المخرج Total: 66. تجد كل خلية هذه المرة القيمة التي تحتاج إليها.

قد تحتفظ نواة قديمة بمتغيرات من تجارب سابقة. وعندئذ يمكن لخلية تُنفّذ قبل أوانها أن تعرض عددًا بدلًا من إظهار خطأ. توضّح التجربة التالية لماذا لا يكفي غياب الخطأ لإثبات صحة الحساب.

لماذا قد تستمر نتيجة قديمة في الظهور؟

تحسب التعليمة total_heures = sum(heures_etude) المجموع باستخدام القائمة المتاحة لحظة تنفيذها. يبقى العدد الناتج مُسندًا إلى total_heures. ولا يؤدي تعديل القائمة لاحقًا إلى إعادة الحساب تلقائيًا.

احتفظ الآن بالقيمتين الأوليين فقط، ثم اعرض المجموع المحفوظ من دون إعادة تنفيذ حسابه.

# Keep only the first two observations.
heures_etude = heures_etude[:2]
print("Current hours:", heures_etude)
Current hours: [23, 19]
# This instruction does not recalculate the total.
print("Stored total:", total_heures)
Stored total: 66

أصبحت القائمة [23, 19]، بينما لا تزال قيمة total_heures هي 66. الاسمان موجودان، لذلك يستطيع Python عرضهما من دون خطأ. لكن هذا المجموع حُسب من القائمة السابقة المكوّنة من ثلاث قيم.

أعد تنفيذ الحساب ليتوافق المجموع مع البيانات الحالية.

# Recalculate the total after changing the input.
total_heures = sum(heures_etude)
print("Recalculated total:", total_heures)
Recalculated total: 42
تحتوي القائمة المختصرة على 23 و19. يبقى المجموع المحفوظ 66 إلى أن تعيد حسابه، فيصبح 42.
بعد اختصار القائمة إلى 23 و19، يبقى المجموع المحفوظ 66. تعيد عملية الجمع حسابه ليصبح 42.

تعطي إعادة الحساب 42، أي 23 + 19. ويحدث الاختلاف نفسه إذا استبدلت القائمة في خلية البيانات بـ[23, 19]، ثم أعدت تنفيذ التحضير والعرض ونسيت خلية الحساب.

إعادة التشغيل، إيقاف التنفيذ أو مسح المخرجات

لكل أمر غرض مختلف. تجد هذه الأوامر في شريط أدوات Notebook أو قائمته في VS Code، بالأسماء Restart، Interrupt وClear All Outputs.

الإجراءالأثرما الذي ينبغي معرفته؟
مسح المخرجاتيزيل النتائج الظاهرة من المستند.تبقى متغيرات النواة متاحة.
إيقاف تنفيذ الخلية (Interrupt)يطلب إيقاف تنفيذ الخلية الجارية.لا يعيد تشغيل النواة أو يمحو ذاكرتها. وتبقى آثار التعليمات التي نُفّذت قبل الإيقاف، بما فيها تغييرات قيم المتغيرات.
إعادة تشغيل النواةتبدأ النواة بذاكرة جديدة، وتحتاج إلى إعادة تنفيذ الخلايا التي تعرّف المتغيرات وتستورد المكتبات.لا تحذف الملف المحفوظ أو الحزم المثبّتة. وقد تظل مخرجات قديمة ظاهرة.
تنفيذ جميع الخلاياينفّذ الخلايا بحسب ترتيبها في المستند.لا يضمن وحده إعادة تهيئة النواة قبل التنفيذ.
أثر الأوامر على الحساب والعرض.

لا يؤدي حذف خلية من المستند إلى إزالة الكائنات التي أنشأتها مسبقًا في نواة Jupyter. قد تبقى هذه الكائنات متاحة حتى إعادة التشغيل، فتخفي اعتمادًا لم يعد ظاهرًا في الملف.

التحقّق من Notebook في نواة جديدة

قبل مشاركة Notebook، تحقّق من أنه يعمل بالخلايا والموارد التي سترسلها. تساعد إعادة تشغيل النواة، ثم تنفيذ جميع الخلايا، على اكتشاف متغير عُرّف في خلية محذوفة مثلًا.

  1. احفظ الكود الحالي باستخدام Ctrl + S.
  2. تحقّق من النواة المختارة أعلى اليمين، ثم أعد تشغيلها.
  3. استخدم Run All لتنفيذ جميع الخلايا بدءًا من الأولى.
  4. تحقّق من المخرجات. إذا فشلت خلية، حدّد أول خطأ وصحّح سببه قبل إعادة الخطوات.
  5. اضغط Ctrl + S مجددًا لحفظ Notebook مع المخرجات التي تحقّقت منها.
احفظ الكود، أعد تشغيل النواة، نفّذ جميع الخلايا، تحقّق من المخرجات، ثم اضغط Ctrl + S لحفظ Notebook مع مخرجاته.
بعد التحقّق من المخرجات، اضغط Ctrl + S مجددًا لحفظ Notebook مع النتائج المعروضة. يحتفظ ملف .ipynb بالكود وهذه المخرجات.

الخطوة الخامسة: حفظ Notebook مع مخرجاته

المخرج ما تعرضه الخلية بعد التنفيذ، مثل نص، عدد، جدول أو رسم بياني. في هذه الخطوة الأخيرة، تحفظ ملف .ipynb مجددًا ليحتفظ بالكود والمخرجات التي تحقّقت منها.

خذ الخلية التي تعرض Total: 66. نفّذها، احفظ Notebook، أغلق المستند ثم أعد فتحه: يمكنك أن تقرأ Total: 66 تحت الخلية. هذا النص أثر للتنفيذ محفوظ في الملف، كما توضّح وثائق صيغة Notebook.

الاحتفاظ بهذا العرض لا يحفظ ذاكرة النواة. إذا بدأت نواة جديدة، يجب إعادة إنشاء total_heures بتنفيذ خلايا تحضير البيانات وحساب المجموع. يسمح لك الملف بقراءة النتيجة السابقة، ويسمح تنفيذ الكود مجددًا بإعادة إنتاجها.

تمرين: اكتشاف اعتماد ناقص

أعد تشغيل النواة وتوقّع ما سيحدث إذا نفّذت فقط print("Total:", total_heures). هل سيكون الاسم total_heures معرّفًا في النواة الجديدة؟ نفّذ الخلية من دون خلايا التحضير، ثم اشرح ما الذي كان سيتغيّر لو مسحت المخرجات فقط.

اكتب بعد ذلك خلية مستقلة تعرّف القيم الثلاث الأولى، تحسب مجموعها وتعرضه. يجب أن تعرض النتيجة نفسها كلما أعدت تنفيذها، من دون الاعتماد على متغير جرى تحضيره في موضع آخر.

اعرض الحل مع الشرح

بعد إعادة التشغيل، لا يكون total_heures معرّفًا، فيرفع Python خطأ NameError. يظهر أدناه السطر الأخير من الرسالة. يوفّر تتبّع الخطأ الكامل، المسمّى traceback، معلومات عن الخلية المعنية أيضًا.

print("Total:", total_heures)
NameError: name 'total_heures' is not defined

لو مسحت المخرجات فقط وكان total_heures معرّفًا مسبقًا في النواة النشطة، لبقي متاحًا بآخر قيمة له، ولأمكن عرض المجموع من دون تحضير جديد. أما إذا لم يكن معرّفًا، فسيظل تنفيذ خلية العرض يسبب خطأ NameError.

تجمع هذه الخلية البيانات، الحساب والعرض. ولا تعتمد نتيجتها على متغير جرى تحضيره في موضع آخر.

# Keep the input and its calculation together to avoid a hidden dependency.
heures_etude = [23, 19, 24]
total_heures = sum(heures_etude)
print("Verified total:", total_heures)
Verified total: 66

يتحقّق هذا الحل من الحساب البسيط في التمرين. وفي Notebook مكوّن من عدة خلايا، طبّق المنطق نفسه على كل ما تعتمد عليه تلك الخلايا.

ما الذي تتحقّق منه إذا لم يعمل Notebook كما تتوقّع؟

العَرَضسبب محتملأول تحقّق
NameErrorلم تُنفّذ خلية التعريف، تغيّر الاسم، أو توجد غلطة في كتابته.راجع الاسم ونفّذ الخلية التي تعرّفه.
نتيجة قديمة من دون خطأتغيّرت قيمة إدخال ولم يُعَد تنفيذ الحساب الذي يعتمد عليها.أعد حساب النتائج المعنية، ثم اختبرها في نواة جديدة.
خطأ في الاستيرادالحزمة غير موجودة في Python المختار، أو اختيرت نواة أخرى.تحقّق من sys.executable وراجع دليل التثبيت.
استمرار حالة الانشغالحساب طويل أو حلقة لا تنتهي.أوقف تنفيذ الخلية، ثم افحصها قبل تشغيلها مجددًا.
بقاء المخرجات بعد إعادة التشغيلالنتيجة محفوظة في المستند.أعد تنفيذ الخلية، فظهور مخرجاتها لا يثبت وجود متغيراتها في الذاكرة.
أعراض تساعدك على تحديد سبب المشكلة.

ما تتذكّره

توفّر .venv برنامج Python وحزم المشروع، وتتيح ipykernel لهذا البرنامج العمل كنواة Jupyter. تحتفظ النواة بالمتغيرات في ذاكرتها، بينما يحفظ ملف Notebook الخلايا والمخرجات المحفوظة. لذلك قد تظل نتيجة ظاهرة رغم أن النواة الجديدة لا تحتوي على متغيراتك. نفّذ الخلايا بحسب اعتمادها بعضها على بعض، وأعد الحسابات المعنية بعد كل تعديل. وقبل مشاركة المستند، أعد تشغيل النواة، نفّذ جميع الخلايا، تحقّق من المخرجات ثم احفظه.

مراجع للتوسّع