مشكلة وحل 28: حل خطأ list indices must be integers or slices, not str في بايثون

حل خطأ list indices must be integers or slices not str في بايثون

قد تكتب كودًا بسيطًا للتعامل مع قائمة، ثم تظهر أمامك الرسالة:

TypeError: list indices must be integers or slices, not str

هذه الرسالة تعني أن لديك قائمة List وحاولت الوصول إلى عنصر منها باستخدام نص من نوع str، بينما القوائم في بايثون تعتمد على فهارس رقمية مثل 0 و1 و2 أو على slice.

يظهر الخطأ كثيرًا في ثلاث حالات: استخدام مفتاح نصي مع List كما لو كانت Dictionary، استخدام القيمة القادمة من input() مباشرة كفهرس، والتعامل مع بيانات JSON التي تكون في الحقيقة قائمة من القواميس وليست قاموسًا واحدًا.

في مشكلة وحل 28 سنفهم رسالة الخطأ، ونحدد نوع المتغير قبل إصلاحه، ونوضح الفرق بين list[index] وdict[key]، ثم نطبق الحل على أمثلة من الإدخال وJSON وList of Dictionaries.

{alertInfo} الحل المختصر: إذا كان المتغير List فاستخدم فهرسًا رقميًا مثل items[0] وليس مفتاحًا نصيًا مثل items["name"]. وإذا جاء الفهرس من input() فحوّله إلى int بعد التحقق منه. وإذا كانت لديك قائمة من القواميس، فاختر عنصر القائمة أولًا ثم المفتاح: users[0]["name"].

{getToc} $title={محتوى المقال}

ما معنى list indices must be integers or slices, not str؟

الجزءالمعنى
TypeErrorاستخدمت نوع بيانات غير مناسب للعملية.
list indicesالمشكلة مرتبطة بفهرسة قائمة.
must be integers or slicesالقائمة تحتاج فهرسًا رقميًا أو Slice.
not strالفهرس الذي مررته كان نصًا.

بمعنى أبسط: أنت تعاملت مع List بطريقة تناسب Dictionary أو استخدمت نصًا بدل رقم.

أبسط مثال يسبب الخطأ

names = ["Ali", "Sara", "Omar"]

print(names["0"])

القيمة "0" نص وليست عددًا. الصحيح:

print(names[0])

الناتج:

Ali

الفرق بين "0" و0

print(type("0"))
print(type(0))

الناتج:

<class 'str'>
<class 'int'>

القيمة تبدو رقمًا للإنسان، لكن علامات الاقتباس تجعلها نصًا في بايثون.

كيف تعمل فهارس List؟

names = ["Ali", "Sara", "Omar"]

print(names[0])
print(names[1])
print(names[2])

الفهرسة تبدأ من صفر. لذلك العنصر الأول رقمه 0 والثاني 1.

ما المقصود بـslices؟

الـSlice تسمح باختيار جزء من القائمة:

numbers = [10, 20, 30, 40]

print(numbers[1:3])

الناتج:

[20, 30]

الفرق بين List وDictionary

القائمة تستخدم موقع العنصر، بينما القاموس يستخدم مفتاحًا.

names = ["Ali", "Sara"]

print(names[0])

أما القاموس:

user = {
    "name": "Ali",
    "city": "Aden"
}

print(user["name"])

لذلك names["name"] خطأ؛ لأن names قائمة وليست قاموسًا.

الفرق بين فهرس القائمة ومفتاح القاموس في بايثون

كيف أعرف نوع المتغير؟

استخدم type() بدل التخمين:

data = ["Ali", "Sara"]

print(type(data))

إذا ظهر <class 'list'> فاستخدم قواعد القوائم. وإذا ظهر <class 'dict'> فيمكن استخدام مفاتيح القاموس.

السبب الأول: استخدام مفتاح نصي مع قائمة

products = ["Keyboard", "Mouse"]

print(products["product"])

هذا غير صحيح لأن products List. إذا كنت تريد أول عنصر:

print(products[0])

أما إذا كنت تحتاج الوصول إلى قيمة باسم "product"، فربما بنية Dictionary هي الأنسب:

product = {
    "name": "Keyboard",
    "price": 80
}

print(product["name"])

السبب الثاني: input ترجع نصًا

هذه من أشهر حالات الخطأ:

colors = ["red", "green", "blue"]

index = input("اختر رقم العنصر: ")

print(colors[index])

حتى لو كتب المستخدم 1، فإن input() تعيد "1" من نوع str.

الحل

index = int(input("اختر رقم العنصر: "))

print(colors[index])
سبب ظهور list indices must be integers عند استخدام input مع قائمة

التحويل وحده لا يكفي في البرامج الحقيقية

إذا كتب المستخدم كلمة بدل رقم، سيظهر ValueError. لذلك الأفضل التحقق:

raw_index = input("اختر رقم العنصر: ").strip()

try:
    index = int(raw_index)
except ValueError:
    print("يجب إدخال رقم صحيح.")
    raise SystemExit

ثم تحقق من حدود القائمة:

if 0 <= index < len(colors):
    print(colors[index])
else:
    print("رقم العنصر خارج حدود القائمة.")

الفرق بين TypeError وIndexError

الخطأالمشكلة
list indices must be integers...نوع الفهرس نفسه غير صحيح.
list index out of rangeالفهرس رقمي لكنه يشير إلى موقع غير موجود.
colors["1"]  # TypeError
colors[99]   # IndexError

السبب الثالث: List of Dictionaries

هذه الحالة مهمة جدًا في JSON وواجهات API:

users = [
    {
        "name": "Ali",
        "city": "Aden"
    },
    {
        "name": "Sara",
        "city": "Sanaa"
    }
]

المتغير users قائمة، لذلك هذا خطأ:

print(users["name"])

الحل الصحيح

print(users[0]["name"])

النتيجة:

Ali

اقرأ التعبير على مرحلتين: users[0] يعيد أول قاموس، ثم ["name"] يأخذ قيمة المفتاح من ذلك القاموس.

الوصول إلى القواميس داخل قائمة بيانات JSON في بايثون

الوصول إلى جميع الأسماء

for user in users:
    print(user["name"])

داخل الحلقة، user هو Dictionary واحدة، لذلك المفتاح النصي صحيح.

خطأ شائع داخل for loop

for i in users:
    print(users[i]["name"])

المتغير i ليس رقم فهرس، بل هو القاموس نفسه. الصحيح:

for user in users:
    print(user["name"])

وإذا كنت تحتاج رقم الفهرس:

for index, user in enumerate(users):
    print(index, user["name"])

السبب الرابع: بيانات JSON ليست بالشكل الذي توقعته

لنفترض أن ملف JSON يحتوي:

[
    {"name": "Ali"},
    {"name": "Sara"}
]

بعد القراءة:

import json

with open("users.json", "r", encoding="utf-8") as file:
    data = json.load(file)

print(type(data))

ستكون data قائمة. لذلك:

print(data[0]["name"])

وليس:

print(data["name"])

أما إذا كان JSON قاموسًا

{
    "name": "Ali",
    "city": "Aden"
}

عندها يكون هذا صحيحًا:

print(data["name"])

السبب الخامس: استجابة API تعيد List بدل Dictionary

قد تتوقع أن الاستجابة قاموس، لكن API تعيد قائمة من النتائج. الحل ليس تغيير السطر عشوائيًا، بل فحص البنية:

print(type(data))
print(data)

إذا كانت List، افحص أول عنصر:

if data:
    print(type(data[0]))
    print(data[0])

بيانات متداخلة: List داخل Dictionary والعكس

data = {
    "users": [
        {
            "name": "Ali",
            "phones": ["111", "222"]
        }
    ]
}

للوصول إلى أول رقم:

print(data["users"][0]["phones"][0])

حلل كل مستوى وفق نوعه: Dictionary ← List ← Dictionary ← List.

طريقة تشخيص الخطأ خطوة بخطوة

عندما ترى رسالة الخطأ، لا تبدأ بتحويل القيم عشوائيًا. نفذ الخطوات التالية:

  1. حدد التعبير الذي يحتوي الأقواس [].
  2. اطبع نوع المتغير الموجود قبل الأقواس.
  3. إذا كان List، افحص نوع الفهرس.
  4. إذا كانت List of Dictionaries، اختر عنصر القائمة أولًا.
  5. إذا كانت البيانات من JSON أو API، افحص بنيتها الفعلية.
  6. إذا جاء الفهرس من input، حوّله إلى int بعد التحقق.
  7. بعد إصلاح النوع، تحقق من حدود القائمة حتى لا يظهر IndexError.
print(type(data))

if isinstance(data, list) and data:
    print(type(data[0]))
    print(data[0])

لماذا لا يصلح استخدام get() على List؟

قد يحاول المبتدئ استبدال:

data["name"]

بـ:

data.get("name")

لكن إذا كانت data List فهذه ليست طريقة صحيحة أيضًا؛ لأن get() من methods القواميس.

كيف أبحث عن عنصر بالاسم داخل List؟

إذا كانت القائمة تحتوي قواميس:

for user in users:
    if user["name"] == "Sara":
        print(user)

ويمكن الحصول على أول نتيجة باستخدام:

result = next(
    (
        user
        for user in users
        if user["name"] == "Sara"
    ),
    None
)

print(result)

هل يمكن استخدام فهرس سالب؟

نعم، لأنه integer:

names = ["Ali", "Sara", "Omar"]

print(names[-1])

الناتج Omar.

هل يمكن استخدام float كفهرس؟

لا:

names[1.0]

قد تظهر رسالة تنتهي بـnot float. القاعدة نفسها: القائمة تحتاج فهرسًا مناسبًا.

أخطاء شائعة عند محاولة الحل

1. تحويل أي نص إلى int

إذا كتبت users["name"] فالمشكلة ليست أن كلمة name تحتاج تحويلًا إلى رقم؛ المشكلة أنك تتعامل مع القائمة ببنية خاطئة.

2. استخدام get() على List

.get() مناسبة للقواميس، لا للقوائم.

3. افتراض أن JSON دائمًا Dictionary

افحص النوع والبنية قبل الوصول إلى القيم.

4. استخدام input مباشرة

input() تعيد نصًا حتى لو كتب المستخدم رقمًا.

5. الخلط بين القائمة والعنصر داخلها

في List of Dictionaries، المفتاح النصي ينتمي إلى القاموس الداخلي وليس إلى List الخارجية.

6. إصلاح TypeError ثم تجاهل IndexError

بعد تحويل الإدخال إلى رقم، تحقق أن الرقم داخل حدود القائمة.

أخطاء شائعة تسبب list indices must be integers or slices not str في بايثون

مثال عملي كامل: اختيار مستخدم من قائمة

users = [
    {"name": "Ali", "city": "Aden"},
    {"name": "Sara", "city": "Sanaa"},
    {"name": "Omar", "city": "Taiz"}
]

for index, user in enumerate(users):
    print(index, user["name"])

raw_choice = input("اختر رقم المستخدم: ").strip()

try:
    choice = int(raw_choice)
except ValueError:
    print("الرجاء إدخال رقم صحيح.")
    raise SystemExit

if 0 <= choice < len(users):
    selected_user = users[choice]

    print("الاسم:", selected_user["name"])
    print("المدينة:", selected_user["city"])
else:
    print("الرقم خارج حدود القائمة.")

هذا المثال يعالج نوع الإدخال وحدود القائمة، ثم يستخدم مفتاح القاموس بعد اختيار عنصر List الصحيح.

مثال عملي مع JSON

import json

with open("users.json", "r", encoding="utf-8") as file:
    users = json.load(file)

print(type(users))

if isinstance(users, list) and users:
    print(users[0]["name"])

جدول تشخيص سريع

الكودالمشكلةالتصحيح
items["0"]الفهرس نص.items[0]
items[input(...)]input تعيد str.تحويل الإدخال إلى int بعد التحقق.
users["name"]users قائمة من القواميس.users[0]["name"] أو البحث داخل القائمة.
data["id"] بعد JSONdata قد تكون List.افحص type(data) والبنية.
items[1.5]float ليست فهرسًا صالحًا للقائمة.استخدم integer صحيحًا إذا كان ذلك منطقيًا.

الفرق بين هذه المشكلة وtoo many values to unpack

الخطأالسبب
list indices must be integers or slices, not strاستخدام نوع غير مناسب كفهرس للقائمة.
too many values to unpackعدد القيم أكبر من عدد المتغيرات المستقبلة.

روابط داخلية مفيدة من بايثون العرب

مصادر رسمية للتوسع

الخلاصة

رسالة TypeError: list indices must be integers or slices, not str تعني أن الكود استخدم نصًا كفهرس لقائمة. القوائم تعتمد على مواقع رقمية أو slices، بينما القواميس تستخدم مفاتيح مثل "name".

إذا جاء الفهرس من input() فتذكر أن الإدخال نص. وإذا جاءت البيانات من JSON أو API فلا تفترض أنها Dictionary؛ افحص النوع والبنية. وفي List of Dictionaries، اختر عنصر القائمة أولًا ثم استخدم مفتاح القاموس.

{alertSuccess} القاعدة المهمة: عندما ترى هذا الخطأ، لا تغيّر الأقواس أو تحوّل القيم عشوائيًا. اطبع نوع البيانات أولًا واسأل: هل لدي List أم Dictionary؟ ثم استخدم طريقة الوصول المناسبة.

أسئلة شائعة

ما معنى list indices must be integers or slices, not str في بايثون؟

تعني أنك استخدمت قيمة نصية كفهرس لقائمة، بينما القائمة تحتاج فهرسًا من نوع integer أو slice.

كيف أحل TypeError list indices must be integers or slices not str؟

افحص نوع المتغير باستخدام type(). إذا كان List فاستخدم فهرسًا رقميًا. وإذا كانت قائمة من القواميس فاختر عنصرًا أولًا ثم استخدم المفتاح، مثل users[0]["name"].

لماذا items["0"] لا تعمل بينما items[0] تعمل؟

لأن "0" نص من نوع str، أما 0 فهو integer صالح لفهرسة القائمة.

لماذا يظهر الخطأ عند استخدام input مع قائمة؟

لأن input() تعيد نصًا دائمًا. إذا كنت تريد استخدام الإدخال كفهرس، حوّله إلى int بعد التحقق من صحة القيمة.

ما الفرق بين فهرس List ومفتاح Dictionary؟

List تستخدم مواقع رقمية مثل 0 و1، بينما Dictionary تستخدم مفاتيح مثل "name".

كيف أصل إلى name داخل List of Dictionaries؟

استخدم users[0]["name"] لأول عنصر، أو مر على القائمة بحلقة واستخدم user["name"].

لماذا يظهر الخطأ عند قراءة JSON؟

غالبًا لأن JSON أعاد List لكن الكود تعامل معها كأنها Dictionary. استخدم type(data) وافحص أول عنصر.

كيف أعرف إذا كانت بيانات JSON قائمة أم قاموسًا؟

بعد القراءة استخدم type(data). إذا ظهر list تعامل معها كقائمة، وإذا ظهر dict استخدم مفاتيح القاموس.

ما الفرق بين هذا الخطأ وIndexError list index out of range؟

TypeError يعني أن نوع الفهرس غير صحيح، بينما IndexError يعني أن الفهرس رقمي لكنه خارج حدود القائمة.

كيف أبحث عن عنصر بالاسم داخل List؟

إذا كانت القائمة تحتوي قواميس، مر على العناصر باستخدام for أو استخدم next() للعثور على القاموس المطلوب.

هل يمكن استخدام مفتاح نصي مع List؟

لا بالطريقة العادية. إذا كنت تحتاج الوصول بالقيم الاسمية فقد تكون Dictionary أو List of Dictionaries هي بنية البيانات المناسبة.

كيف أتجنب الخطأ عند التعامل مع API؟

افحص شكل الاستجابة الفعلي قبل كتابة منطق الوصول، ولا تفترض أن البيانات قاموس دون التحقق من النوع والبنية.

إرسال تعليق

أحدث أقدم