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 zensure_ascii=Falsedaje 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:
| Python | JSON |
|---|---|
dict | obiekt |
list, tuple | tablica |
str | napis |
int, float | liczba |
True | true |
False | false |
None | null |
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=2dla plików czytanych przez ludzi: konfiguracji, danych testowych, eksportów. Pomijaj go w ruchu sieciowym, gdzie liczy się rozmiar. - Ustaw
ensure_ascii=Falseprzy 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ą.