AttributeError („obiekt 'str' nie ma atrybutu 'odczyt'”)

142

W Pythonie pojawia się błąd:

Exception:  (<type 'exceptions.AttributeError'>,
AttributeError("'str' object has no attribute 'read'",), <traceback object at 0x1543ab8>)

Podany kod Pythona:

def getEntries (self, sub):
    url = 'http://www.reddit.com/'
    if (sub != ''):
        url += 'r/' + sub

    request = urllib2.Request (url + 
        '.json', None, {'User-Agent' : 'Reddit desktop client by /user/RobinJ1995/'})
    response = urllib2.urlopen (request)
    jsonofabitch = response.read ()

    return json.load (jsonofabitch)['data']['children']

Co oznacza ten błąd i co zrobiłem, aby go wywołać?

RobinJ
źródło
6
Ha ha! Co to za „jsonofabitch”? : D
Bahadir Tasdemir
14
Wygląda na to, że moderatorzy Stackoverflow mają poczucie humoru, dla odmiany ...
Pepito Fernandez
6
2019 i to wciąż jest zabawne: P
Rishav
1
Rzeczywiście, zrobiłem mój dzień, dziękuję z przyszłości :)
Pesche Helfer

Odpowiedzi:

194

Problem polega na tym, json.loadże powinieneś przekazać plik podobny do obiektu ze readzdefiniowaną funkcją. Więc albo używasz json.load(response)albo json.loads(response.read()).

kosii
źródło
3
Nie rozumiem tego ... w jaki sposób funkcja read () rozwiązuje problem? Odpowiedź nadal nie ma funkcji odczytu. Czy mamy umieścić napis w jakimś obiekcie z funkcją odczytu?
zakdances
92
@yourfriendzak przeczytaj uważnie, są to dwie różne funkcje o bardzo podobnych nazwach. json.load()pobiera plik jak obiekt z read()metodą, json.loads()pobiera ciąg. Łatwo przeoczyć „s” na końcu i pomyśleć, że to ta sama metoda.
Joshmaker
4
Dzięki komentarzowi Joshmakera, json.loads () może analizować ciąg znaków dla danych JSON!
Yu Shen
2
@yourfriendzak Ta odpowiedź wskazuje, że openmożesz to osiągnąć.
chaim
1
@MANISHZOPE soznacza „ciąg”. Zgadzam się, że biblioteka standardowa ma ogólnie poważne problemy z nazywaniem rzeczy i jest to dobry przykład tego, jak się zepsuła.
Karl Knechtel,
14
AttributeError("'str' object has no attribute 'read'",)

Oznacza to dokładnie to, co jest napisane: coś próbowało znaleźć .readatrybut na obiekcie, który mu nadałeś, i nadałeś mu obiekt typu str(tj. Nadałeś mu łańcuch).

Wystąpił błąd tutaj:

json.load (jsonofabitch)['data']['children']

Cóż, nie szukasz readnigdzie, więc musi się to zdarzyć w json.loadwywołanej funkcji (na co wskazuje pełne śledzenie). To dlatego, że json.loadstara się .reado rzeczy, które dał, ale dałeś go jsonofabitch, co obecnie nazwy ciąg (który został utworzony przez wywołanie .readna response).

Rozwiązanie: nie wzywaj .readsiebie; funkcja zrobi to i oczekuje, że podasz jej responsebezpośrednio, aby mogła to zrobić.

Mogłeś to również ustalić, czytając wbudowaną dokumentację Pythona dla funkcji (spróbuj help(json.load)lub dla całego modułu (try help(json)), lub sprawdzając dokumentację tych funkcji na http://docs.python.org .

Karl Knechtel
źródło
Tak nazwał to OP. Zawsze się zastanawiam, czy zmienić lub zachować takie nazwy identyfikatorów, pomagając innym. : /
Karl Knechtel
Och, masz rację,
przejrzałem
14

Jeśli pojawi się taki błąd Pythona:

AttributeError: 'str' object has no attribute 'some_method'

Prawdopodobnie przypadkowo zatrułeś obiekt, nadpisując go łańcuchem.

Jak odtworzyć ten błąd w Pythonie za pomocą kilku wierszy kodu:

#!/usr/bin/env python
import json
def foobar(json):
    msg = json.loads(json)

foobar('{"batman": "yes"}')

Uruchom go, który drukuje:

AttributeError: 'str' object has no attribute 'loads'

Ale zmień nazwę nazwy zmiennej i działa dobrze:

#!/usr/bin/env python
import json
def foobar(jsonstring):
    msg = json.loads(jsonstring)

foobar('{"batman": "yes"}')

Ten błąd jest spowodowany próbą uruchomienia metody w ciągu. String ma kilka metod, ale nie tę, którą wywołujesz. Więc przestań próbować wywołać metodę, której String nie definiuje i zacznij szukać, gdzie zatrułeś swój obiekt.

Eric Leschinski
źródło
7

Ok, to stary wątek, ale. Miałem ten sam problem, mój problem został użyty json.loadzamiastjson.loads

W ten sposób json nie ma problemu z ładowaniem dowolnego rodzaju słownika.

Oficjalna dokumentacja

json.load - Deserialize fp (a .read () - pomocniczy plik tekstowy lub plik binarny zawierający dokument JSON) do obiektu Pythona przy użyciu tej tabeli konwersji.

json.loads - Deserialize s (instancja typu str, bytes lub bytearray zawierająca dokument JSON) do obiektu Pythona przy użyciu tej tabeli konwersji.

JohnyMSF
źródło
7

Najpierw musisz otworzyć plik. To nie działa:

json_file = json.load('test.json')

Ale to działa:

f = open('test.json')
json_file = json.load(f)
Richard Liang
źródło
2
Znalazłem błąd w pytaniu podczas próby otwarcia pliku zamiast odpowiedzi na pytanie. Najwyraźniej na zapleczu json traktuje oba w podobny sposób, więc ta odpowiedź mi pomogła. Zdecydowanie warte uznania.
Nitin Khanna