👨💻 شكوى الأخ "أحمد":
"مرحبًا ، أنا أحمد، مبتدئ في تعلم بايثون. كنت أحاول كتابة برنامج يستخرج معلومات من قاموس (Dictionary) معقد، لكن البرنامج يتوقف فجأة ويُظهر لي خطأ غريبًا: TypeError: 'NoneType' object is not subscriptable. فتشت في الكود كثيرًا ولم أجد أي خطأ إملائي. السطر يبدو لي صحيحًا. أرجو المساعدة!"
✅ الحل المختصر للمشكلة
مرحبًا أحمد،
المشكلة ليست في صيغة الكود نفسه، بل في البيانات التي يتعامل معها الكود. باختصار شديد، أنت تحاول الوصول إلى جزء من متغير قيمته الحالية هي None (لا شيء).
الحل المباشر: أضف جملة شرطية if للتأكد من أن المتغير ليس فارغًا قبل استخدامه.
بدلاً من كتابة هذا الكود الخاطئ:
بياناتي = دالة_ما()print(بياناتي['اسمي']) # <--- الخطأ يحدث هنا لو كانت بياناتي = None
استخدم هذا الكود الصحيح:
بياناتي = دالة_ما()# الحل: التحقق من أن المتغير ليس Noneif بياناتي is not None:print(بياناتي['اسمي'])else:print("لم يتم العثور على بيانات.")
انتهى الأمر. بهذا التعديل البسيط سيتوقف الخطأ فورًا.
📚 الشرح الكامل للمشكلة وتفاصيلها (لمن يريد فهم الأسباب)
بعد أن قدمنا الحل السريع، دعنا نفهم ماذا كان يحدث خلف الكواليس حتى تتعلم كيفية تجنب هذا الخطأ نهائيًا في المستقبل.
1. تشريح رسالة الخطأ
رسالة الخطأ التي ظهرت لك هي صديقك الحقيقي، دعنا نحللها:
- TypeError: يعني أنك تحاول القيام بعملية غير مسموحة على نوع معين من البيانات.
- 'NoneType' object: هذا يعني أن القيمة التي تحاول التعامل معها من النوع NoneType. القيمة الوحيدة من هذا النوع في بايثون هي الكلمة المفتاحية None (التي تعني فراغ أو لا شيء).
- is not subscriptable: كلمة "Subscriptable" تعني "قابل للفهرسة باستخدام الأقواس المربعة []". القوائم والنصوص والقواميس قابلة للفهرسة. أما الكائن None فهو ليس قابلاً للفهرسة لأنه لا يحتوي على عناصر أصلاً.
الخلاصة: أنت قلت للحاسوب "أعطني العنصر الموجود داخل هذا الشيء"، لكن هذا الشيء كان فارغًا (None).
2. متى يحدث هذا الخطأ في المشاريع الحقيقية؟
هذا الخطأ شائع جدًا في منصات مثل GitHub وStack Overflow (وخاصة Reddit)، ويحدث غالبًا في الحالات التالية:
- استدعاء دالة ترجع None: دوال كثيرة في بايثون ترجع None كقيمة افتراضية عند الفشل (مثل dict.get(key) لو المفتاح غير موجود، أو دوال قراءة الملفات لو الملف فارغ).
- نسيان كلمة return في الدالة: لو عرّفت دالة ونسيت كتابة return، فإن بايثون تلقائيًا ترجع None عند انتهائها.
- العمل مع دوال تقوم بتعديل القوائم في مكانها: مثال شهير هو دالة ()list.sort، هذه الدالة ترتب القائمة وترجع None، فلا يصح أن تكتب: قائمتي = قائمتي.()sort.
3. مثال توضيحي من بيئة العمل
تخيل أنك تبحث عن طالب في قاعدة بيانات. الدالة مكتوبة بهذا الشكل:
def البحث_عن_طالب(الرقم_الجامعي):if الرقم_الجامعي == 123:return {"الاسم": "أحمد", "التقدير": "جيد جداً"}# إذا لم نجد الطالب... ماذا سنرجع؟ سنرجع Nonereturn None# المشكلة:بيانات_احمد = البحث_عن_طالب(999) # لا يوجد طالب بهذا الرقم# الآن المتغير بيانات_احمد أصبح Noneprint(بيانات_احمد["الاسم"]) # <--- هنا سيظهر الخطأ الذي واجهته أنت!
4. طرق إضافية للتعامل مع المشكلة (للمحترفين)
طريقة استخدام try-except:
هذه الطريقة مفيدة إذا كنت تريد منع البرنامج من الانهيار وعرض رسالة مخصصة.
try:print(بيانات_احمد["الاسم"])except TypeError:print("عذراً، بيانات الطالب غير موجودة أو فارغة.")
طريقة استخدام get في القواميس:
لو كنت تتعامل مع قاموس غير متأكد من وجوده، فهذه الطريقة آمنة 100%:
# لو كان القاموس موجوداً نستخدم get، ولو كان None سنعطيه قاموساً فارغاً مؤقتاً الاسم = (بيانات_احمد or {}).get("الاسم", "غير معروف") print(الاسم)
نصائح "بايثون العرب" الذهبية
- لا تثق أبدًا بالمدخلات: سواء كانت من دوال خارجية أو من ملفات أو من المستخدم، تحقق دائمًا من أن القيمة ليست None.
- إقرأ رسالة الخطأ بتمعن: هي تخبرك بالضبط في أي سطر حدثت المشكلة وما هو نوع الكائن الخاطئ.
- استخدم print للتصحيح: إذا شككت في قيمة متغير، اطبعها على الشاشة قبل استخدامها في عملية الفهرسة.
نتمنى أن يكون الرد شافيًا. إذا كان لديك أي استفسار آخر، قسم التعليقات في خدمتك دائمًا. وإلى لقاء قريب في مشكلة وحل جديدة!
