من الأخطاء التي تربك المبتدئين في بايثون خطأ:
TypeError: 'NoneType' object is not subscriptable
خصوصًا عندما يظهر أثناء التعامل مع القوائم أو القواميس أو نتائج الدوال.
في هذا الدرس من سلسلة مشكلة وحل على بايثون العرب سنشرح معنى الخطأ ببساطة، ولماذا يحدث، وكيف تصلحه بطريقة صحيحة بدل أن تبحث طويلًا داخل الكود بدون معرفة السبب الحقيقي.
{getToc} $title={محتوى المقال}
{alertInfo} هذا الخطأ يعني غالبًا أنك تحاول استخدام الأقواس المربعة [] على قيمة فارغة من النوع None، بينما الفهرسة تعمل مع كائنات مثل list و string و dictionary.
نص المشكلة
تخيل أن مبتدئًا في بايثون كتب برنامجًا يحاول استخراج قيمة من قاموس أو نتيجة دالة، ثم ظهر له الخطأ التالي:
TypeError: 'NoneType' object is not subscriptable
قد يبدو السطر الذي سبب المشكلة صحيحًا من ناحية الشكل، مثل:
print(data["name"])
لكن المشكلة ليست دائمًا في الأقواس أو في اسم المفتاح، بل في قيمة المتغير نفسه. قد تكون قيمة data هي None وليس قاموسًا كما تتوقع.
الحل المختصر
الحل المباشر هو أن تتحقق من أن المتغير ليس None قبل محاولة الوصول إلى عنصر داخله باستخدام الأقواس المربعة.
بدلًا من كتابة هذا الكود مباشرة:
data = get_data()
print(data["name"])
اكتب شرطًا بسيطًا قبل استخدام الفهرسة:
data = get_data()
if data is not None:
print(data["name"])
else:
print("لم يتم العثور على بيانات.")
{alertSuccess} الفكرة الأساسية: قبل أن تستخدم [] تأكد أن المتغير يحتوي فعلًا على قائمة أو قاموس أو نص، وليس None.
ما معنى NoneType object is not subscriptable؟
لنفهم الرسالة جزءًا جزءًا:
| جزء الخطأ | المعنى |
|---|---|
TypeError |
يعني أنك تحاول تنفيذ عملية غير مناسبة على نوع بيانات معيّن. |
NoneType |
يعني أن الكائن الذي تتعامل معه قيمته None. |
object is not subscriptable |
يعني أن هذا الكائن لا يمكن استخدام الأقواس المربعة [] معه. |
بمعنى أبسط: أنت تطلب من بايثون أن يعطيك عنصرًا داخل شيء فارغ أصلًا.
ما المقصود بـ subscriptable في بايثون؟
الكائن القابل للفهرسة هو الكائن الذي يمكنك الوصول إلى عناصره باستخدام الأقواس المربعة [].
أمثلة على كائنات تدعم الفهرسة:
names = ["Ali", "Omar", "Sara"]
print(names[0])
text = "Python"
print(text[0])
student = {"name": "Ali"}
print(student["name"])
أما None فلا يحتوي على عناصر، لذلك لا يمكن كتابة:
data = None
print(data["name"])
وهنا سيظهر الخطأ:
TypeError: 'NoneType' object is not subscriptable
مثال عملي يوضح سبب الخطأ
لنفترض أن لدينا دالة تبحث عن طالب حسب الرقم الجامعي. إذا وجدت الطالب ترجع قاموسًا، وإذا لم تجده ترجع None.
def find_student(student_id):
if student_id == 123:
return {
"name": "Ahmed",
"grade": "Very Good"
}
return None
student = find_student(999)
print(student["name"])
في المثال السابق، الرقم 999 غير موجود، لذلك الدالة سترجع None. بعد ذلك حاولنا الوصول إلى:
student["name"]
لكن student ليس قاموسًا، بل قيمته None، لذلك يظهر الخطأ.
الحل الصحيح للمثال السابق
نضيف شرطًا قبل الوصول إلى قيمة name:
def find_student(student_id):
if student_id == 123:
return {
"name": "Ahmed",
"grade": "Very Good"
}
return None
student = find_student(999)
if student is not None:
print(student["name"])
else:
print("لم يتم العثور على الطالب.")
بهذا الشكل لن ينهار البرنامج، وسيعرض رسالة واضحة عندما لا توجد بيانات.
أسباب ظهور هذا الخطأ في بايثون
هذا الخطأ قد يظهر في أكثر من حالة، وأشهر أسبابه هي:
- دالة ترجع
Noneبدلًا من قاموس أو قائمة. - نسيان كتابة
returnداخل الدالة. - محاولة استخدام نتيجة دالة لا ترجع قيمة.
- استخدام دوال تعدل الكائن في مكانه وترجع
Noneمثلlist.sort(). - البحث عن عنصر غير موجود ثم استخدام النتيجة مباشرة بدون تحقق.
مثال شائع: نسيان return داخل الدالة
إذا كتبت دالة ولم تضع فيها return، فإن بايثون ترجع None تلقائيًا.
def get_user():
user = {"name": "Ali"}
# نسينا return هنا
result = get_user()
print(result["name"])
الكود السابق سيؤدي إلى نفس الخطأ؛ لأن result أصبح None.
التصحيح:
def get_user():
user = {"name": "Ali"}
return user
result = get_user()
print(result["name"])
{alertWarning} إذا كانت الدالة يجب أن تعطيك نتيجة، فتأكد أنها تحتوي على return في جميع الحالات المناسبة.
مثال شائع: استخدام list.sort بطريقة خاطئة
من الأخطاء الشائعة أن يكتب المبتدئ:
numbers = [3, 1, 2]
sorted_numbers = numbers.sort()
print(sorted_numbers[0])
المشكلة أن sort() ترتب القائمة الأصلية في مكانها، لكنها لا ترجع قائمة جديدة، بل ترجع None.
الحل الأول:
numbers = [3, 1, 2]
numbers.sort()
print(numbers[0])
أو استخدم sorted() إذا كنت تريد قائمة جديدة:
numbers = [3, 1, 2]
sorted_numbers = sorted(numbers)
print(sorted_numbers[0])
استخدام get بطريقة آمنة مع القواميس
إذا كنت تتعامل مع قاموس وقد لا تكون البيانات موجودة، يمكنك استخدام get() بطريقة آمنة:
student = None
name = (student or {}).get("name", "غير معروف")
print(name)
هنا استخدمنا:
student or {}
حتى إذا كانت قيمة student هي None، يتم استخدام قاموس فارغ بدلًا منها.
هل try-except حل مناسب؟
يمكن استخدام try-except لمنع توقف البرنامج، لكنه ليس دائمًا أفضل حل للمبتدئ. الأفضل غالبًا أن تفهم لماذا أصبحت القيمة None وتصلح السبب من المصدر.
مثال:
try:
print(student["name"])
except TypeError:
print("البيانات غير موجودة أو فارغة.")
{alertInfo} استخدم try-except عند الحاجة، لكن لا تجعله يخفي المشكلة الأساسية. الأفضل أن تعرف لماذا المتغير أصبح None.
كيف تعرف المتغير الذي قيمته None؟
أسهل طريقة للمبتدئ هي طباعة قيمة المتغير قبل استخدامه:
print(student)
print(type(student))
إذا كانت النتيجة:
None
<class 'NoneType'>
فهذا يعني أن المشكلة في قيمة المتغير قبل سطر الفهرسة، وليس في الأقواس نفسها.
ملخص سريع للحل
| السبب | الحل |
|---|---|
| المتغير قيمته None | تحقق منه باستخدام if value is not None. |
| الدالة لا ترجع قيمة | أضف return مناسبًا داخل الدالة. |
| استخدام sort بطريقة خاطئة | استخدم list.sort() بدون تخزين النتيجة، أو استخدم sorted(). |
| البيانات قد تكون غير موجودة | استخدم get() أو قيمة افتراضية. |
روابط مفيدة من بايثون العرب
- شرح return في دوال بايثون للمبتدئين
- شرح القوائم Lists في بايثون
- شرح القواميس Dictionaries في بايثون
- حل خطأ can only concatenate str not int to str في بايثون
- جميع مقالات سلسلة مشكلة وحل في بايثون
الخلاصة
خطأ NoneType object is not subscriptable يحدث عندما تحاول استخدام الأقواس المربعة [] على قيمة None. الحل ليس حذف الأقواس مباشرة، بل معرفة لماذا أصبح المتغير None من الأساس.
قبل الوصول إلى عناصر القوائم أو القواميس، تحقق من قيمة المتغير، واستخدم return بشكل صحيح داخل الدوال، وانتبه للدوال التي تعدل الكائن في مكانه مثل sort().
{alertSuccess} القاعدة الذهبية: إذا ظهر لك هذا الخطأ، اطبع قيمة المتغير ونوعه قبل سطر الخطأ، وستعرف بسرعة هل تتعامل مع None بدلًا من قائمة أو قاموس.