Menu

JSON w Pythonie: odczyt, zapis i parsowanie JSON z modułem json

Jak czytać i zapisywać JSON w Pythonie: loads, dumps, odczyt z plików, ładne formatowanie i przypadki brzegowe, które pojawiają się przy prawdziwych danych.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

JSON i Python mówią tymi samymi kształtami

JSON to domyślny format dla API, plików konfiguracyjnych i wymiany danych w sieci. Na szczęście dla programistów Pythona obiekt JSON odpowiada bezpośrednio słownikowi (dict), tablica JSON liście, a napis JSON typowi str. Właśnie dzięki temu dopasowaniu odczyt i zapis JSON w Pythonie to operacja na dwie linijki.

Moduł json z biblioteki standardowej obsługuje oba kierunki.

Parsowanie napisu JSON

json.loads(text) ("load string") przyjmuje napis w formacie JSON i zwraca obiekt Pythona, który ten napis opisuje:

Wynik to zwykły słownik. Do kluczy odwołujesz się jak w każdym słowniku: bez specjalnej otoczki JSON i bez metody .parse() na wyniku.

Jeśli napis nie jest poprawnym JSON, json.loads zgłasza json.JSONDecodeError. Komunikat błędu zawiera wiersz i kolumnę problemu, co zwykle wystarcza, żeby znaleźć brakujący przecinek albo niezescapowany cudzysłów.

Zapis JSON jako napisu

json.dumps(data) ("dump string") robi odwrotnie: przyjmuje obiekt Pythona i zwraca napis JSON:

Pythonowe True, False i None są automatycznie zamieniane na true, false i null z JSON. Liczby i napisy przechodzą bez zmian. Listy stają się tablicami, a słowniki obiektami.

Ładne formatowanie (pretty print)

Domyślny wynik json.dumps jest zwarty: dobry do przesyłania przez sieć, trudny do czytania dla ludzi. Przekaż indent=2, żeby dostać coś czytelniejszego:

Kilka innych opcji dumps, które warto znać:

  • sort_keys=True: sortuje klucze obiektów alfabetycznie. Przydaje się, gdy wynik ma być deterministyczny (pliki konfiguracyjne, dane testowe, porównywanie zmian).
  • ensure_ascii=False: zapisuje znaki spoza ASCII (é, ü, 中) wprost, a nie jako sekwencje \u. Zwykle właściwy wybór dla plików UTF-8.
  • separators=(",", ":"): najbardziej zwarty możliwy wynik. W połączeniu z ensure_ascii=False daje najkrótszy JSON w UTF-8, jaki da się uzyskać.

Odczyt JSON z pliku

json.load(file) (bez s) czyta bezpośrednio z obiektu pliku. Typowy wzorzec łączy go z with open:

import json

with open("config.json") as f:
    config = json.load(f)

print(config["version"])

Nie musisz najpierw wczytywać całego pliku do napisu; json.load czyta prosto z obiektu pliku.

Zapis JSON do pliku

json.dump(data, file) to odpowiednik do zapisu w pliku:

import json

data = {"created": "2026-01-01", "items": [1, 2, 3]}

with open("state.json", "w") as f:
    json.dump(data, f, indent=2)

Opcja indent działa tu tak samo. Otwórz powstały plik, a zobaczysz ładnie sformatowany dokument JSON.

Odczyt odpowiedzi z API w JSON

Większość bibliotek HTTP daje ci bajty albo tekst; wywołujesz json.loads, żeby zamienić je na dane, z którymi da się pracować:

import json
import urllib.request

with urllib.request.urlopen("https://api.example.com/users/1") as response:
    text = response.read().decode("utf-8")

user = json.loads(text)
print(user["name"])

Biblioteka requests (opisana osobno) pomija jeden krok: odpowiedź ma metodę .json(), która wywołuje json.loads za ciebie.

Co JSON potrafi zapisać, a czego nie

System typów JSON jest węższy niż w Pythonie. Odwzorowanie w obu kierunkach:

PythonJSON
dictobiekt
list, tupletablica
strnapis
int, floatliczba
Truetrue
Falsefalse
Nonenull

Krotki wracają jako listy, więc informacja, że to była krotka, ginie. Zbiorów, własnych klas i obiektów datetime domyślnie nie da się zserializować; dostajesz TypeError: Object of type X is not JSON serializable.

Obsługa datetime i własnych obiektów

Są dwa popularne podejścia.

Najpierw zamień dane na strukturę bezpieczną dla JSON. Zrób przekształcenie we własnym kodzie, a potem zserializuj zwykły słownik:

Przekaż funkcję default=. json.dumps wywołuje ją dla każdej wartości, której nie umie zserializować:

Przy ponownym odczycie danych musisz samodzielnie zamienić te napisy ISO z powrotem na datetime, bo JSON nie pamięta, czym były pierwotnie.

Słownik tam i z powrotem przez JSON

Szybki test, że słowniki przechodzą przez JSON bez strat:

Wartości są równe, ale to różne obiekty. Często właśnie o to chodzi: json.dumps + json.loads to tani sposób na głęboką kopię dowolnej struktury zgodnej z JSON.

Realistyczny przykład

Mały skrypt, który wczytuje konfigurację z JSON, zmienia jedno pole i zapisuje ją z powrotem:

import json
from pathlib import Path

config_path = Path("settings.json")

# Wczytaj (z wartością domyślną, jeśli plik nie istnieje).
if config_path.exists():
    config = json.loads(config_path.read_text())
else:
    config = {"theme": "dark", "last_opened": None}

# Zaktualizuj.
config["last_opened"] = "2026-01-15"

# Zapisz, ładnie sformatowane.
config_path.write_text(json.dumps(config, indent=2, ensure_ascii=False))

To pełny cykl "odczyt, zmiana, zapis" dla JSON w kilkunastu linijkach.

Kilka nawyków

  • Do plików zawsze używaj with open(...). JSON to zwykły tekst, więc obowiązują wszystkie zasady pracy z plikami.
  • Wybieraj indent=2 dla plików czytanych przez ludzi: konfiguracji, danych testowych, eksportów. Pomijaj go w ruchu sieciowym, gdzie liczy się rozmiar.
  • Ustaw ensure_ascii=False przy zapisie w UTF-8, żeby nazwy z polskimi znakami czy innymi znakami spoza alfabetu łacińskiego pozostały czytelne.
  • Sprawdzaj dane przez try/except json.JSONDecodeError, gdy parsujesz dane, które nie pochodzą od ciebie.

Co dalej

JSON obsługuje dane typu klucz-wartość. Kolejne narzędzie w tym samym rozdziale to CSV, czyli wbudowana obsługa w Pythonie formatu tabelarycznego, na którym opiera się większość eksportów z arkuszy kalkulacyjnych.

Najczęściej zadawane pytania

Jak sparsować JSON w Pythonie?

Użyj json.loads(text) dla napisu JSON albo json.load(file) dla obiektu pliku. Obie funkcje zwracają słownik Pythona (lub listę, zależnie od JSON). Przykład: po data = json.loads('{"name": "Rosa"}') wartość data['name'] to 'Rosa'.

Jak zamienić słownik Pythona na JSON?

json.dumps(my_dict) zwraca napis JSON. json.dump(my_dict, file) zapisuje bezpośrednio do obiektu pliku. Przekaż indent=2, aby dostać ładnie sformatowany wynik: json.dumps(data, indent=2).

Czym różni się json.loads od json.load?

loads (z literą s) przyjmuje napis. load (bez s) przyjmuje obiekt pliku. Tak samo jest z dumps i dump. Litera s oznacza string; to najprostszy sposób, żeby zapamiętać, która funkcja jest która.

Jak obsłużyć daty i własne obiekty w JSON?

JSON nie ma typu daty, więc przekazuj daty jako napisy ISO-8601 i parsuj je z powrotem ręcznie. W przypadku własnych klas przekaż do json.dumps funkcję default=, która zwraca reprezentację bezpieczną dla JSON, albo samodzielnie zamień obiekt na dict przed serializacją.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ