Dlaczego widzę „TypeError: indeksy ciągów muszą być liczbami całkowitymi”?

219

Gram zarówno z nauką Pythona, jak i próbowaniem przekształcenia problemów z github w czytelną formę. Korzystając ze porady dotyczącej sposobu konwersji JSON na CSV? Wymyśliłem to:

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

Gdzie „Issues.json” to plik json zawierający moje problemy z github. Kiedy próbuję to uruchomić, rozumiem

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

Czego tu brakuje? Jakie są „indeksy ciągów”? Jestem pewien, że kiedy już zacznę działać, będę mieć więcej problemów, ale na razie chciałbym, żeby to zadziałało!

Kiedy poprawiam foroświadczenie po prostu

for item in data:
    print item

dostaję ... „problemy” - więc robię coś bardziej podstawowego, złego. Oto trochę mojego Jsona:

{"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...

kiedy datadrukuję, wygląda to na dziwnie mungowane:

{u'issues': [{u'body': u'Add missing paging (Older>>) lin...
Amanda
źródło
Brakuje tego print repr(data)lubimport pprint; pprint.pprint(data)
John Machin

Odpowiedzi:

116

itemjest najprawdopodobniej łańcuchem w twoim kodzie; indeksy ciągów są tymi w nawiasach kwadratowych, np gravatar_id. Więc najpierw sprawdzę twoją datazmienną, aby zobaczyć, co tam otrzymałeś; Sądzę, że datajest to lista ciągów (lub przynajmniej lista zawierająca co najmniej jeden ciąg), podczas gdy powinna to być lista słowników.

Tamás
źródło
158

Zmienna itemjest ciągiem. Indeks wygląda następująco:

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

W powyższym przykładzie użyto 0indeksu ciągu w celu odniesienia do pierwszego znaku.

Ciągi nie mogą mieć indeksów ciągów (podobnie jak słowniki). Więc to nie zadziała:

>>> mystring = 'helloworld'
>>> print mystring['stringindex']
TypeError: string indices must be integers
bluepnume
źródło
42

datajest dictprzedmiotem. Powtórz to tak:

Python 2

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

Python 3

for key, value in data.items():
    print(key, value)
John Machin
źródło
36

TypeError for Slice Notation str[a:b]

tl; dr: użyj dwukropka : zamiast przecinka pomiędzy dwoma indeksami ai binstr[a:b]


Podczas pracy z notacjami ciągów i wycinków ( wspólna operacja sekwencji ) może się zdarzyć, że a TypeErrorzostanie podniesione, wskazując, że indeksy muszą być liczbami całkowitymi, nawet jeśli oczywiście są.

Przykład

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

Oczywiście do notacji plastra przekazaliśmy dwie liczby całkowite dla indeksów, prawda? Więc w czym jest problem?

Ten błąd może być bardzo frustrujący - szczególnie na początku nauki języka Python - ponieważ komunikat o błędzie jest nieco mylący.

Wyjaśnienie

Niejawnie przekazaliśmy krotkę dwóch liczb całkowitych (0 i 5) do notacji wycinka, gdy wywołaliśmy, my_string[0,5]ponieważ 0,5(nawet bez nawiasów) oblicza tę samą krotkę, co (0,5)by to zrobiło .

Przecinek ,wystarczy, aby Python mógł ocenić coś jako krotkę:

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

Więc co tam zrobiliśmy, tym razem wyraźnie:

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

Teraz przynajmniej komunikat o błędzie ma sens.

Rozwiązanie

Musimy zastąpić przecinek , z jelita grubego : do oddzielenia tych dwóch liczb całkowitych poprawnie:

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

Jaśniejszy i bardziej pomocny komunikat o błędzie mógłby wyglądać następująco:

TypeError: string indices must be integers (not tuple)

Dobry komunikat o błędzie pokazuje użytkownikowi bezpośrednio, co zrobił źle, i byłoby bardziej oczywiste, jak rozwiązać problem.

[Następnym razem, gdy okaże się, że jesteś odpowiedzialny za napisanie komunikatu o błędzie, pomyśl o tym przykładzie i dodaj przyczynę lub inne przydatne informacje do komunikatu o błędzie, aby pozwolić Tobie i innym osobom zrozumieć, co poszło nie tak.]

Zdobyta wiedza

  • notacja plastra używa dwukropków :do oddzielenia swoich wskaźników (i zakresu kroków, np. str[from:to:step])
  • krotki są zdefiniowane przecinkami ,(np. t = 1,)
  • dodaj informacje do komunikatów o błędach, aby użytkownicy zrozumieli, co poszło nie tak

Pozdrawiam i wesołego programowania
winklerrr


[Wiem, że na to pytanie już udzielono odpowiedzi i nie było to dokładnie pytanie zadane przez podmiot rozpoczynający wątek, ale przybyłem tutaj z powodu powyższego problemu, który prowadzi do tego samego komunikatu o błędzie. Znalezienie tej małej literówki zajęło mi przynajmniej trochę czasu.

Mam więc nadzieję, że pomoże to komuś, kto natknął się na ten sam błąd i zaoszczędzi im trochę czasu na znalezienie tego drobnego błędu]

winklerrr
źródło
0

Może się to zdarzyć, jeśli brakuje przecinka. Natknąłem się na to, gdy miałem listę dwóch krotek, z których każda składała się ze sznurka na pierwszej pozycji i listy na drugiej. Pomyłkowo pominąłem przecinek po pierwszym elemencie krotki w jednym przypadku, a tłumacz pomyślał, że próbuję zindeksować pierwszy element.

dumbledad
źródło
0

Miałem podobny problem z Pandas, musisz użyć funkcji iterrows () do iteracji przez zestaw danych Pandas Dokumentacja Pandas dla iterrows

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

zwróć uwagę, że musisz obsłużyć indeks w zbiorze danych, który jest również zwracany przez funkcję.

coremonkey
źródło