¿Por qué veo "TypeError: los índices de cadena deben ser enteros"?

219

Estoy jugando con Python aprendiendo y tratando de obtener problemas de github en una forma legible. Usando el consejo sobre ¿Cómo puedo convertir JSON a CSV? Se me ocurrió esto:

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","votes","created_at","comments","body","title","updated_at","html_url","user","labels","state"])

for item in data:
        csv_file.writerow([item["gravatar_id"], item["position"], item["number"], item["votes"], item["created_at"], item["comments"], item["body"], item["title"], item["updated_at"], item["html_url"], item["user"], item["labels"], item["state"]])

Donde "issues.json" es el archivo json que contiene mis problemas de github. Cuando trato de ejecutar eso, me sale

File "foo.py", line 14, in <module>
csv_file.writerow([item["gravatar_id"], item["position"], item["number"], item["votes"], item["created_at"], item["comments"], item["body"], item["title"], item["updated_at"], item["html_url"], item["user"], item["labels"], item["state"]])

TypeError: string indices must be integers

¿Que me estoy perdiendo aqui? ¿Cuáles son los "índices de cadena"? Estoy seguro de que una vez que funcione, tendré más problemas, pero por ahora, ¡me encantaría que esto funcione!

Cuando modifico la fordeclaración simplemente

for item in data:
    print item

lo que obtengo es ... "problemas", así que estoy haciendo algo más básico mal. Aquí hay un poco de mi json:

{"issues":[{"gravatar_id":"44230311a3dcd684b6c5f81bf2ec9f60","position":2.0,"number":263,"votes":0,"created_at":"2010/09/17 16:06:50 -0700","comments":11,"body":"Add missing paging (Older>>) links...

cuando dataimprimo parece que se está machacando realmente extraño:

{u'issues': [{u'body': u'Add missing paging (Older>>) lin...
Amanda
fuente
Lo que te falta es print repr(data)oimport pprint; pprint.pprint(data)
John Machin

Respuestas:

116

itemes muy probable que sea una cadena en su código; los índices de cuerdas son las de los corchetes, por ejemplo, gravatar_id. Así que primero verificaría tu datavariable para ver qué recibiste allí; Supongo que dataes una lista de cadenas (o al menos una lista que contiene al menos una cadena) mientras que debería ser una lista de diccionarios.

Tamás
fuente
158

La variable itemes una cadena. Un índice se ve así:

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

El ejemplo anterior usa el 0índice de la cadena para referirse al primer carácter.

Las cadenas no pueden tener índices de cadena (como los diccionarios pueden). Entonces esto no funcionará:

>>> mystring = 'helloworld'
>>> print mystring['stringindex']
TypeError: string indices must be integers
bluepnume
fuente
42

dataEs un dictobjeto. Entonces, repítelo así:

Python 2

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

Python 3

for key, value in data.items():
    print(key, value)
John Machin
fuente
36

TypeError para la notación de corte str[a:b]

tl; dr: use dos puntos en : lugar de una coma entre los dos índices ay benstr[a:b]


Cuando se trabaja con cadenas y notación de corte (una operación de secuencia común ), puede suceder que TypeErrorse levante a, señalando que los índices deben ser enteros, incluso si obviamente lo son.

Ejemplo

>>> my_string = "hello world"
>>> my_string[0,5]
TypeError: string indices must be integers

Obviamente pasamos dos enteros para los índices a la notación de corte, ¿verdad? Entonces, ¿cuál es el problema aquí?

Este error puede ser muy frustrante, especialmente al comienzo del aprendizaje de Python, porque el mensaje de error es un poco engañoso.

Explicación

Implícitamente pasamos una tupla de dos enteros (0 y 5) a la notación de corte cuando llamamos my_string[0,5]porque 0,5(incluso sin los paréntesis) se evalúa a la misma tupla como (0,5)lo haría.

Una coma ,es en realidad suficiente para que Python evalúe algo como una tupla:

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

Entonces, lo que hicimos allí, esta vez explícitamente:

>>> my_string = "hello world"
>>> my_tuple = 0, 5
>>> my_string[my_tuple]
TypeError: string indices must be integers

Ahora, al menos, el mensaje de error tiene sentido.

Solución

Necesitamos reemplazar la coma , con dos puntos : para separar los dos enteros correctamente:

>>> my_string = "hello world"
>>> my_string[0:5]
'hello'

Un mensaje de error más claro y útil podría haber sido algo como:

TypeError: string indices must be integers (not tuple)

Un buen mensaje de error muestra al usuario directamente lo que hizo mal y hubiera sido más obvio cómo resolver el problema.

[Entonces, la próxima vez que te encuentres responsable de escribir un mensaje de descripción de error, piensa en este ejemplo y agrega la razón u otra información útil al mensaje de error para que tú y otras personas entiendan lo que salió mal.]

Lecciones aprendidas

  • La notación de corte utiliza dos puntos :para separar sus índices (y rango de pasos, por ejemplo str[from:to:step])
  • las tuplas se definen con comas ,(p t = 1,. ej. )
  • agregue información a los mensajes de error para que los usuarios comprendan qué salió mal

Saludos y feliz programación
winklerrr


[Sé que esta pregunta ya fue respondida y esta no fue exactamente la pregunta que hizo el iniciador del hilo, pero vine aquí debido al problema anterior que conduce al mismo mensaje de error. Al menos me llevó bastante tiempo encontrar ese pequeño error tipográfico.

Así que espero que esto ayude a alguien que se topó con el mismo error y les ahorre algo de tiempo para encontrar ese pequeño error.]

winklerrr
fuente
0

Esto puede suceder si falta una coma. Me encontré con él cuando tenía una lista de dos tuplas, cada una de las cuales consistía en una cadena en la primera posición, y una lista en la segunda. Por error, omití la coma después del primer componente de una tupla en un caso, y el intérprete pensó que estaba tratando de indexar el primer componente.

dumbledad
fuente
0

Tuve un problema similar con Pandas, debe usar la función iterrows () para iterar a través de un conjunto de datos de Pandas Documentación de Pandas para iterrows

data = pd.read_csv('foo.csv')
for index,item in data.iterrows():
    print('{} {}'.format(item["gravatar_id"], item["position"]))

tenga en cuenta que debe manejar el índice en el conjunto de datos que también devuelve la función.

coremonkey
fuente