Вопрос-Ответ

Why am I seeing "TypeError: string indices must be integers"?

Почему я вижу "TypeError: строковые индексы должны быть целыми числами"?

Я играю с изучением Python и пытаюсь привести проблемы GitHub в удобочитаемую форму. Используя советы о том, как я могу преобразовать JSON в CSV?, я придумал это:

import json
import csv

f = open('issues.json')
data = json.load(f)
f.close()

f = open("issues.csv", "wb+")
csv_file = csv.writer(f)

csv_file.writerow(["gravatar_id", "position", "number"])

for item in data:
csv_file.writerow([item["gravatar_id"], item["position"], item["number"]])

Где "issues.json" - это файл JSON, содержащий мои проблемы с GitHub. Когда я пытаюсь запустить это, я получаю

TypeError: string indices must be integers

Чего мне здесь не хватает? Что это за "строковые индексы"?

Вот немного моего содержимого JSON:

{"issues": [{"gravatar_id": "44230311a3dcd684b6c5f81bf2ec9f60", "position": 2.0, "number": 263...
Переведено автоматически
Ответ 1

Переменная item является строкой. Индекс выглядит следующим образом:

>>> mystring = 'helloworld'
>>> print mystring[0]
'h'

В приведенном выше примере используется 0 индекс строки для ссылки на первый символ.

Строки не могут иметь строковых индексов (как это могут делать словари). Так что это не сработает:

>>> mystring = 'helloworld'
>>> print mystring['stringindex']
TypeError: string indices must be integers
Ответ 2

item скорее всего, это строка в вашем коде; строковые индексы - это те, что заключены в квадратные скобки, например, gravatar_id. Поэтому я бы сначала проверил вашу data переменную, чтобы увидеть, что вы там получили; Я предполагаю, что это data список строк (или, по крайней мере, список, содержащий хотя бы одну строку), в то время как это должен быть список словарей.

Ответ 3

TypeError для обозначения фрагментов str[a:b]


Краткий ответ

Используйте двоеточие : вместо запятой , между двумя индексами a и b в str[a:b]:

my_string[0,5]  # wrong ❌
my_string[0:5] # correct ✅

Длинный ответ

При работе со строками и нотацией срезов (обычная операция последовательности) может случиться так, что TypeError выдается a, указывающий на то, что индексы должны быть целыми числами, даже если они, очевидно, таковыми являются.

Example

>>> my_string = "Hello, World!"
>>> my_string[0,5]
TypeError: string indices must be integers

We obviously passed two integers for the indices to the slice notation, right? So what is the problem here?

This error can be very frustrating - especially at the beginning of learning Python - because the error message is a little bit misleading.

Explanation

We implicitly passed a tuple of two integers to the slice notation when we called my_string[0,5]. 0,5 evaluates to the same tuple as (0,5) does - even without the parentheses. Why though?

A trailing comma , is actually enough for the Python interpreter to evaluate something as a tuple:

>>> my_variable = 0,
>>> type(my_variable)
<class 'tuple'>

So what we did there, this time explicitly:

>>> my_string = "Hello, World!"
>>> my_tuple = 0, 5
>>> my_string[my_tuple]
TypeError: string indices must be integers

Now, at least, the error message makes sense.

Solution

We need to replace the comma , with a colon : to separate the two integers correctly, not having them interpreted as a tuple:

>>> my_string = "Hello, World!"
>>> my_string[0:5]
'hello'

A clearer and more helpful error message could have been something like:

TypeError: string indices must be integers not tuple
^^^^^
(actual type here)

A good error message should show the user directly what they did wrong! With this kind of information it would have been much more easier to find the root cause and solve the problem - and you wouldn't have had to come here.

So next time, when you find yourself responsible for writing error description messages, remind yourself of this example and add the reason (or other useful information) to error message! Help other people (or maybe even your future self) to understand what went wrong.

Lessons learned


  • slice notation uses colons : to separate its indices (and step range, i.e., str[from:to:step])

  • tuples are defined by commas , (i.e., t = 1,)

  • add some information to error messages for users to understand what went wrong

Ответ 4

data is a dict object. So, iterate over it like this:

Python 2

for key, value in data.iteritems():
print key, value

Python 3

for key, value in data.items():
print(key, value)
python json