Por que estou vendo "TypeError: índices de string devem ser inteiros"?

219

Estou brincando com o aprendizado de python e tentando obter problemas do github de forma legível. Usando o conselho de Como posso converter JSON em CSV? Eu vim com isso:

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"]])

Onde "issues.json" é o arquivo json que contém meus problemas no github. Quando tento executar isso, recebo

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

O que estou perdendo aqui? Quais são os "índices de string"? Tenho certeza de que, assim que eu conseguir trabalhar, terei mais problemas, mas, por enquanto, adoraria que isso funcionasse!

Quando eu ajusto a forafirmação para simplesmente

for item in data:
    print item

o que eu recebo é ... "problemas" - então estou fazendo algo mais básico errado. Aqui está um pouco do meu 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...

quando imprimo data, parece que está ficando mungo de maneira estranha:

{u'issues': [{u'body': u'Add missing paging (Older>>) lin...
Amanda
fonte
O que você está perdendo é print repr(data)ouimport pprint; pprint.pprint(data)
John Machin

Respostas:

116

itemé provavelmente uma string no seu código; os índices de string são os que estão entre colchetes, por exemplo gravatar_id,. Então, eu primeiro verificaria sua datavariável para ver o que você recebeu lá; Eu acho que dataé uma lista de strings (ou pelo menos uma lista que contém pelo menos uma string), embora deva ser uma lista de dicionários.

Tamás
fonte
158

A variável itemé uma sequência. Um índice é assim:

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

O exemplo acima usa o 0 índice da sequência para se referir ao primeiro caractere.

As strings não podem ter índices de strings (como os dicionários). Portanto, isso não vai funcionar:

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

dataé um dictobjeto. Então, itere sobre o seguinte:

Python 2

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

Python 3

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

TypeError para notação de fatia str[a:b]

tl; dr: use dois pontos em : vez de vírgula entre os dois índices ae bemstr[a:b]


Ao trabalhar com strings e notação de fatia (uma operação comum de sequência ), pode acontecer que umTypeError seja aumentado, indicando que os índices devem ser números inteiros, mesmo que obviamente sejam.

Exemplo

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

Nós obviamente passamos dois números inteiros para os índices para a notação de fatia, certo? Então, qual é o problema aqui?

Esse erro pode ser muito frustrante - especialmente no início do aprendizado de Python - porque a mensagem de erro é um pouco enganadora.

Explicação

Passamos implicitamente uma tupla de dois números inteiros (0 e 5) para a notação de fatia quando chamamos my_string[0,5]porque 0,5(mesmo sem parênteses) é avaliada para a mesma tupla que (0,5)seria.

Uma vírgula ,é realmente suficiente para o Python avaliar algo como uma tupla:

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

Então, o que fizemos lá, desta vez explicitamente:

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

Agora, pelo menos, a mensagem de erro faz sentido.

Solução

Precisamos substituir a vírgula , por dois pontos : para separar os dois números inteiros corretamente:

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

Uma mensagem de erro mais clara e útil poderia ter sido algo como:

TypeError: string indices must be integers (not tuple)

Uma boa mensagem de erro mostra diretamente ao usuário o que ele fez de errado e teria sido mais óbvio como resolver o problema.

[Portanto, na próxima vez em que você for responsável por escrever uma mensagem de descrição de erro, pense neste exemplo e adicione o motivo ou outras informações úteis à mensagem de erro para permitir que você e outras pessoas entendam o que deu errado.]

Lições aprendidas

  • A notação de fatia usa dois pontos :para separar seus índices (e intervalo de etapas, por exemplo,str[from:to:step] )
  • tuplas são definidas por vírgulas ,(por exemplo t = 1,)
  • adicione algumas informações às mensagens de erro para que os usuários entendam o que deu errado

Felicidades e feliz programação
winklerrr


[Eu sei que esta pergunta já foi respondida e essa não foi exatamente a pergunta que o iniciador de threads fez, mas eu vim aqui por causa do problema acima, que leva à mesma mensagem de erro. Pelo menos, levei algum tempo para encontrar esse pequeno erro de digitação.

Então, espero que isso ajude alguém que tenha encontrado o mesmo erro e economize algum tempo para encontrar esse pequeno erro.]

winklerrr
fonte
0

Isso pode acontecer se uma vírgula estiver faltando. Eu o encontrei quando tinha uma lista de duas tuplas, cada uma das quais consistia em uma corda na primeira posição e uma lista na segunda. Omiti erroneamente a vírgula após o primeiro componente de uma tupla em um caso, e o intérprete achou que eu estava tentando indexar o primeiro componente.

dumbledad
fonte
0

Eu tive um problema semelhante com o Pandas, você precisa usar a função iterrows () para iterar através de um conjunto de dados do Pandas Documentação do Pandas para iterrows

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

Observe que você precisa manipular o índice no conjunto de dados que também é retornado pela função.

coremonkey
fonte