JSON Formatter Python — Poradnik json.dumps()
Użyj darmowego Formater i Upiększacz JSON bezpośrednio w przeglądarce — bez instalacji.
Wypróbuj Formater i Upiększacz JSON online →Kiedy debuguję klienta Python API, pierwszą rzeczą po którą sięgam jest python pretty print json — jedno wywołanie json.dumps(data, indent=4) zamienia nieczytelny blob w jednej linii w coś natychmiast przejrzystego. Wbudowany moduł json Pythona obsługuje to całkowicie w standardowej bibliotece — bez instalacji zewnętrznych pakietów. Jeśli potrzebujesz szybkiego wyniku bez pisania kodu, Formater JSON od ToolDeck zrobi to natychmiast. Ten przewodnik omawia wszystkie praktyczne metody: json.dumps() ze wszystkimi parametrami, pprint, orjson do wydajnego formatowania, CLI json.tool, serializację niestandardowych typów jak datetime i UUID, strumieniowe przetwarzanie plików gigabajtowych z ijson, i podświetlanie składni w terminalu z rich — wszystko z kodem kompatybilnym z Python 3.8+.
- →
json.dumps(data, indent=4)jest wbudowane w stdlib Pythona od wersji 2.6 — nie wymaga instalacji. - →Przekaż
ensure_ascii=Falsegdy dane zawierają polskie litery, znaki akcentowane, znaki CJK lub emoji. - →Dla
datetime,UUIDlub klas niestandardowych użyj parametrudefault=lub dziedzicz pojson.JSONEncoder. - →
separators=(',', ':')usuwa wszystkie spacje — używaj do przesyłania sieciowego lub osadzania w URL. - →
orjsonjest 5–10× szybszy niż stdlib i natywnie obsługujedatetimeiuuid.UUID. - →
pprint.pprint()produkuje składnię Pythona (True/None), nie prawidłowy JSON — nigdy nie używaj do plików ani odpowiedzi API. - →Dla plików JSON większych niż 50 MB użyj strumieniowania z
ijsonzamiastjson.load(), aby uniknąćMemoryError.
Czym jest ładne drukowanie JSON?
Ładne drukowanie przekształca gęsty, zminifikowany ciąg JSON w czytelny dla człowieka format ze spójnym wcięciem i podziałami linii. Transformacja jest czysto kosmetyczna: dane są identyczne, zmienia się tylko prezentacja. Moduł json Pythona obsługuje to całkowicie w standardowej bibliotece — nic do zainstalowania.
{"id":"usr_9f3a2b","name":"Piotr Kowalski","roles":["admin","editor"],"prefs":{"theme":"dark","lang":"pl"}}{
"id": "usr_9f3a2b",
"name": "Piotr Kowalski",
"roles": [
"admin",
"editor"
],
"prefs": {
"theme": "dark",
"lang": "pl"
}
}json.dumps() — Standardowy sposób formatowania JSON
json.dumps() jest częścią standardowej biblioteki Pythona od wersji 2.6 — wystarczy import json, bez instalacji. Serializuje dowolny kompatybilny z JSON obiekt Pythona do sformatowanego ciągu. Kluczowym parametrem jest indent: ustaw go na 4 (lub 2), aby uzyskać czytelne wyjście.
import json
uzytkownik = {
"id": "usr_9f3a2b",
"name": "Piotr Kowalski",
"roles": ["admin", "editor"],
"prefs": {"theme": "dark", "lang": "pl"}
}
print(json.dumps(uzytkownik, indent=4, ensure_ascii=False))
# Wyjście:
# {
# "id": "usr_9f3a2b",
# "name": "Piotr Kowalski",
# "roles": [
# "admin",
# "editor"
# ],
# "prefs": {
# "theme": "dark",
# "lang": "pl"
# }
# }Do użytku produkcyjnego często będziesz chciał sort_keys=True (spójne wyjście między uruchomieniami) i ensure_ascii=False (zachowanie polskich znaków):
import json
odpowiedz_api = {
"timestamp": "2024-05-01T10:30:00Z",
"status": "sukces",
"dane": {
"user_id": "usr_9f3a2b",
"nazwa_uzytkownika": "Anna Wiśniewska",
"miasto": "Warszawa",
"wynik": 4892.5,
"tagi": ["python", "backend", "api"]
}
}
print(json.dumps(odpowiedz_api, indent=4, sort_keys=True, ensure_ascii=False))
# Wyjście (klucze posortowane, polskie znaki zachowane):
# {
# "dane": {
# "miasto": "Warszawa",
# "nazwa_uzytkownika": "Anna Wiśniewska",
# "tagi": ["api", "backend", "python"],
# "user_id": "usr_9f3a2b",
# "wynik": 4892.5
# },
# "status": "sukces",
# "timestamp": "2024-05-01T10:30:00Z"
# }json.dumps() zwraca ciąg. Aby zapisać sformatowany JSON bezpośrednio do pliku, użyj json.dump(data, f, indent=4) (bez s) — zapisuje do obiektu pliku i unika tworzenia pośredniego ciągu w pamięci.Dokumentacja parametrów json.dumps()
Wszystkie parametry są opcjonalne poza samym obiektem. Domyślne wartości produkują kompaktowy, bezpieczny dla ASCII JSON — przekaż parametry jawnie dla wyjścia czytelnego dla człowieka.
Kompaktowe wyjście JSON z parametrem separators
Domyślnie json.dumps() oddziela elementy za pomocą ", " a klucze od wartości za pomocą ": ". Parametr separators nadpisuje oba. Przekazanie (',', ':') usuwa wszystkie spacje produkując najbardziej kompaktowy prawidłowy JSON — przydatne do transmisji sieciowej, osadzania w URL lub przechowywania JSON w kolumnie bazy danych gdzie każdy bajt ma znaczenie.
import json
ladunek = {
"endpoint": "/api/v2/zdarzenia",
"filtry": {"status": "aktywny", "limit": 100},
"sortowanie": "desc"
}
# Domyślnie — spacje po separatorach (czytelny)
wyjscie_domyslne = json.dumps(ladunek, ensure_ascii=False)
# {"endpoint": "/api/v2/zdarzenia", "filtry": {"status": "aktywny", "limit": 100}, "sortowanie": "desc"}
# len = 88
# Kompaktowy — bez spacji
wyjscie_kompaktowe = json.dumps(ladunek, separators=(',', ':'), ensure_ascii=False)
# {"endpoint":"/api/v2/zdarzenia","filtry":{"status":"aktywny","limit":100},"sortowanie":"desc"}
# len = 80 (9% mniejszy; oszczędności rosną przy większych, głębiej zagnieżdżonych ładunkach)
# Kompaktowy + posortowane klucze dla odtwarzalnych kluczy cache
kanoniczny = json.dumps(ladunek, separators=(',', ':'), sort_keys=True, ensure_ascii=False)
print(kanoniczny)
# {"endpoint":"/api/v2/zdarzenia","filtry":{"limit":100,"status":"aktywny"},"sortowanie":"desc"}indent= razem z separators=, argument separators kontroluje tylko separatory inline — podziały linii i wcięcia z indent są zachowane. Jeśli chcesz kompaktowego wyjścia w jednej linii, pomiń indent (lub przekaż None) i ustaw separators=(',', ':').Serializacja niestandardowych obiektów Pythona z parametrem default
Standardowy moduł json serializuje słowniki, listy, ciągi, liczby, wartości logiczne i None — ale rzucaTypeError dla każdego innego typu. Dwa najczęstsze problemy w kodzie produkcyjnym to obiekty datetime i UUID.
import json
from datetime import datetime, timezone
import uuid
zamowienie = {
"zamowienie_id": uuid.uuid4(), # ❌ TypeError: UUID is not JSON serializable
"utworzone_o": datetime.now(timezone.utc), # ❌ TypeError: datetime is not JSON serializable
"suma_pln": 142.50,
"pozycje": ["subskrypcja-pro", "dodatek-pamiec"]
}
json.dumps(zamowienie) # rzuca TypeErrorPodejście 1 — parametr default=
Przekaż obiekt wywoływalny do default=. json.dumps() wywołuje go dla każdego obiektu, którego nie może obsłużyć. Zwróć serializowalną reprezentację lub rzuć TypeError dla typów, których nie obsługujesz jawnie — nigdy nie pomijaj nieznanych w ciszy.
import json
from datetime import datetime, timezone, date
import uuid
from decimal import Decimal
def json_domyslny(obj):
if isinstance(obj, (datetime, date)):
return obj.isoformat()
if isinstance(obj, uuid.UUID):
return str(obj)
if isinstance(obj, Decimal):
return float(obj)
raise TypeError(f"Typ {type(obj).__name__!r} nie jest serializowalny do JSON")
zamowienie = {
"zamowienie_id": uuid.uuid4(),
"utworzone_o": datetime(2024, 5, 1, 10, 30, 0, tzinfo=timezone.utc),
"suma_pln": Decimal("142.50"),
"pozycje": ["subskrypcja-pro", "dodatek-pamiec"]
}
print(json.dumps(zamowienie, indent=4, default=json_domyslny, ensure_ascii=False))
# {
# "zamowienie_id": "a3f1c2d4-e5b6-7890-abcd-ef1234567890",
# "utworzone_o": "2024-05-01T10:30:00+00:00",
# "suma_pln": 142.5,
# "pozycje": ["subskrypcja-pro", "dodatek-pamiec"]
# }Podejście 2 — dziedziczenie po json.JSONEncoder
Dla wielokrotnie używanej logiki kodowania współdzielonej między wieloma modułami, dziedziczenie po json.JSONEncoder jest czystsze niż przekazywanie funkcji default wszędzie. Nadpisz metodę default i wywołaj super().default(obj) jako ostatni fallback — zachowuje to poprawne zachowanie błędu dla nieobsługiwanych typów.
import json
from datetime import datetime, timezone
import uuid
from decimal import Decimal
class AppEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
if isinstance(obj, uuid.UUID):
return str(obj)
if isinstance(obj, Decimal):
return float(obj)
return super().default(obj) # rzuca TypeError dla nieznanych typów
zamowienie = {
"zamowienie_id": uuid.uuid4(),
"utworzone_o": datetime(2024, 5, 1, 10, 30, 0, tzinfo=timezone.utc),
"suma_pln": Decimal("142.50"),
}
# Przekaż klasę enkodera przez cls=
print(json.dumps(zamowienie, indent=4, cls=AppEncoder, ensure_ascii=False))
# Identyczne wyjście jak przy podejściu z default=super().default(obj) (lub rzuć jawnie TypeError) dla nierozpoznanych typów. Ciche zwracanie str(obj) dla wszystkiego uszkodzi obiekty, które powinny rzucić błąd — błąd trudny do wyśledzenia w produkcji.Dekodowanie z powrotem — object_hook
Kodowanie to tylko połowa historii. Aby zrekonstruować niestandardowy obiekt Pythona z JSON, przekaż funkcję object_hook do json.loads() lub json.load(). Hook jest wywoływany dla każdego zdekodowanego obiektu JSON (słownika) i może zwrócić dowolną wartość Pythona — dając pełny cykl kodowania ↔ dekodowania.
import json
from datetime import datetime
from dataclasses import dataclass
@dataclass
class Zdarzenie:
nazwa: str
wystapilo_o: datetime
user_id: str
def koduj_zdarzenie(obj):
if isinstance(obj, Zdarzenie):
return {
"__typ__": "Zdarzenie",
"nazwa": obj.nazwa,
"wystapilo_o": obj.wystapilo_o.isoformat(),
"user_id": obj.user_id,
}
raise TypeError(f"Nie można serializować {type(obj)}")
def dekoduj_zdarzenie(d):
if d.get("__typ__") == "Zdarzenie":
return Zdarzenie(
nazwa=d["nazwa"],
wystapilo_o=datetime.fromisoformat(d["wystapilo_o"]),
user_id=d["user_id"],
)
return d
# Koduj
zdarzenie = Zdarzenie("logowanie", datetime(2024, 5, 1, 10, 30), "usr_9f3a2b")
json_str = json.dumps(zdarzenie, default=koduj_zdarzenie, indent=4)
# Dekoduj z powrotem do instancji Zdarzenie
przywrocony = json.loads(json_str, object_hook=dekoduj_zdarzenie)
print(type(przywrocony)) # <class 'Zdarzenie'>
print(przywrocony.wystapilo_o) # 2024-05-01 10:30:00object_hook jest wywoływany dla każdego zagnieżdżonego słownika w dokumencie — nie tylko na najwyższym poziomie. Dołącz pole dyskryminatora (jak "__typ__"), aby hook mógł rozróżnić Twoje niestandardowe obiekty od zwykłych słowników, które powinny pozostać bez zmian.pprint — Alternatywny moduł (i kiedy go nie używać)
Moduł pprint Pythona (pretty printer) formatuje struktury danych Pythona dla czytelności w terminalu. Działa na sparsowanych obiektach Pythona, nie na ciągach JSON — a jego wyjście używa składni Pythona, nie składni JSON.
import json, pprint
raw = '{"sensor_id":"s-441","readings":[23.1,23.4,22.9],"unit":"celsius","active":true}'
data = json.loads(raw)
# pprint — prawidłowy repr Pythona, NIE prawidłowy JSON
pprint.pprint(data, sort_dicts=False)
# {'sensor_id': 's-441',
# 'readings': [23.1, 23.4, 22.9],
# 'unit': 'celsius',
# 'active': True} ← Python True, nie JSON true
# json.dumps — prawidłowy JSON
print(json.dumps(data, indent=4))
# {
# "sensor_id": "s-441",
# "readings": [23.1, 23.4, 22.9],
# "unit": "celsius",
# "active": true ← prawidłowy JSON
# }pprint do punktu końcowego API ani nie zapisuj go do pliku .json — uszkodzi każdy parser JSON oczekujący standardowej składni. Używaj json.dumps(indent=4) do wszystkich wyjść, które muszą być prawidłowym JSON.Kiedy pprint ma sens: szybka inspekcja obiektów Pythona w REPL lub logu debugowania, szczególnie gdy obiekt zawiera typy nieserializowalne do JSON (zbiory, instancje klas niestandardowych, dataclassy przed konwersją).
Jak ładnie wydrukować odpowiedź JSON z Requests
Najczęstszy rzeczywisty scenariusz: masz plik JSON na dysku lub odpowiedź HTTP z API i chcesz ją sformatować do debugowania lub logowania. W obu przypadkach stosuje się to samo podejście — parsuj do słownika Pythona, następnie formatuj za pomocą json.dumps().
Odczyt z pliku
import json
try:
with open("config.json", "r", encoding="utf-8") as f:
data = json.load(f)
# Ładnie wydrukuj do konsoli
print(json.dumps(data, indent=4, ensure_ascii=False))
# Lub zapisz sformatowaną wersję z powrotem na dysk
with open("config.pretty.json", "w", encoding="utf-8") as f:
json.dump(data, f, indent=4, ensure_ascii=False)
except json.JSONDecodeError as e:
print(f"Nieprawidłowy JSON: {e}")
except FileNotFoundError:
print(f"Plik nie znaleziony: config.json")Formatowanie odpowiedzi API
import json, requests
from requests.exceptions import HTTPError, ConnectionError, Timeout
def ladnie_wydrukuj_api(url: str) -> None:
try:
odp = requests.get(url, timeout=10)
odp.raise_for_status()
print(json.dumps(odp.json(), indent=4, ensure_ascii=False))
except HTTPError as e:
print(f"HTTP {e.response.status_code}: {e}")
except (ConnectionError, Timeout) as e:
print(f"Błąd sieci: {e}")
except json.JSONDecodeError:
print(f"Treść odpowiedzi nie jest JSON:\n{odp.text[:500]}")
ladnie_wydrukuj_api("https://api.github.com/repos/python/cpython")response.json() już parsuje treść odpowiedzi — nie trzeba osobno wywoływać json.loads(). Zawsze dodawaj raise_for_status() przed dostępem do .json(), aby przechwycić błędy 4xx/5xx zanim spowodują mylący błąd parsowania.Ładne drukowanie z wiersza poleceń
Python dostarcza json.tool, moduł CLI do formatowania JSON bezpośrednio z terminala — bez potrzeby pisania skryptu Pythona. Jest dostępny na każdej maszynie z zainstalowanym Pythonem.
# Formatuj lokalny plik
python -m json.tool config.json
# Przepuść odpowiedź API przez formater
curl -s https://api.github.com/users/gvanrossum | python -m json.tool
# Formatuj ze stdin
echo '{"serwis":"api-gateway","wersja":"2.1.0","zdrowy":true}' | python -m json.tool
# Sortuj klucze alfabetycznie
python -m json.tool --sort-keys data.json
# Niestandardowe wcięcie (Python 3.9+)
python -m json.tool --indent 2 data.json--indent i --no-indent. Do bardziej zaawansowanego filtrowania JSON w terminalu rozważ jq — ale python -m json.tool obsługuje przypadek użycia formatowania bez żadnych dodatkowych zależności.Jeśli nie jesteś w terminalu — wklejając odpowiedź z Postmana lub plik logów — Formater JSON od ToolDeck pozwala wkleić, sformatować i skopiować w jednym kroku z wbudowanym podświetlaniem składni i walidacją.
Biblioteki alternatywne: orjson i rich
orjson — 5–10× szybszy z natywną obsługą typów
Standardowy moduł json jest wystarczająco szybki dla większości przypadków, ale jeśli serializujesz tysiące obiektów na sekundę — potoki logowania, API o wysokiej przepustowości, duże eksporty danych — orjson jest 5–10× szybszy. Natywnie obsługuje też typy, których standardowa biblioteka nie może serializować bez niestandardowej funkcji default: datetime, uuid.UUID, tablice numpy i dataclassy.
pip install orjson
import orjson
from datetime import datetime, timezone
import uuid
zdarzenie = {
"zdarzenie_id": uuid.uuid4(), # nie trzeba str() — orjson obsługuje UUID
"timestamp": datetime.now(timezone.utc), # nie trzeba isoformat()
"serwis": "auth-service",
"poziom": "INFO",
"ladunek": {
"user_id": "usr_9f3a2b",
"akcja": "logowanie",
"ip": "192.168.1.42",
"opoznienie_ms": 34
}
}
# orjson.dumps zwraca bajty; .decode() konwertuje do str
print(orjson.dumps(zdarzenie, option=orjson.OPT_INDENT_2).decode())
# {
# "zdarzenie_id": "a3f1c2d4-e5b6-7890-abcd-ef1234567890",
# "timestamp": "2024-05-01T10:30:00+00:00",
# "serwis": "auth-service",
# ...
# }Dwie rzeczy do zapamiętania: orjson.dumps() zwraca bytes, nie ciąg — wywołaj .decode() jeśli potrzebujesz ciągu. Obsługuje tylko wcięcie 2-spacyjne przez OPT_INDENT_2; dla wyjścia 4-spacyjnego użyj standardowego json.dumps(indent=4).
rich — Podświetlanie składni w terminalu
Jeśli regularnie sprawdzasz JSON w terminalu lub REPL, rich renderuje kolorowe, podświetlone składniowo wyjście, które czyni głęboko zagnieżdżone struktury czytelnymi na pierwszy rzut oka. Klucze, ciągi, liczby i wartości logiczne mają różne kolory — znacznie łatwiejsze do skanowania niż ściana monochromatycznego tekstu. To narzędzie tylko do debugowania, nie do serializacji produkcyjnej.
pip install rich
from rich import print_json
import json
# print_json() przyjmuje ciąg JSON
raw = '{"zdarzenie":"logowanie","user_id":"usr_9f3a2b","timestamp":"2024-05-01T10:30:00Z","sukces":true,"meta":{"ip":"192.168.1.42","proby":1}}'
print_json(raw)
# Aby ładnie wydrukować słownik Pythona, najpierw przekonwertuj na ciąg
dane = {
"status": "sukces",
"liczba": 42,
"tagi": ["python", "api", "backend"]
}
print_json(json.dumps(dane, ensure_ascii=False))rich.print_json() wyprowadza kody ucieczki ANSI dla koloru terminala — nigdy nie przechwytuj tego wyjścia i nie zapisuj go do pliku .json ani nie wysyłaj jako odpowiedź API. Używaj json.dumps(indent=4) do każdego wyjścia czytalnego maszynowo.simplejson — Bezpośredni zamiennik stdlib
simplejson to biblioteka, która stała się standardowym modułem json Pythona — jest nadal utrzymywana niezależnie i wyprzedza stdlib w drobnych funkcjach. Jest prawdziwym bezpośrednim zamiennikiem: zamień import a reszta kodu pozostaje niezmieniona. Przydatne gdy potrzebujesz obsługi Decimal bez niestandardowego enkodera lub gdy celujesz w starsze środowiska Pythona.
pip install simplejson
import simplejson as json # identyczne API jak stdlib
from decimal import Decimal
zamowienie = {
"pozycja": "Subskrypcja API Kraków",
"cena": Decimal("49.99"), # stdlib json rzuciłby tu TypeError
"ilosc": 3,
}
# simplejson serializuje Decimal natywnie — nie potrzeba default=
print(json.dumps(zamowienie, indent=4, use_decimal=True, ensure_ascii=False))
# {
# "pozycja": "Subskrypcja API Kraków",
# "cena": 49.99,
# "ilosc": 3
# }orjson jest lepszym wyborem. Sięgaj po simplejson gdy potrzebujesz natywnej serializacji Decimal bez pisania niestandardowego enkodera lub gdy utrzymujesz kod bazowy, który już go używa.Przetwarzanie dużych plików JSON bez wyczerpania pamięci
json.load() wczytuje cały plik do pamięci zanim uzyskasz dostęp do jednego pola. Przy pliku z milionami rekordów lub ładunku powyżej gigabajta powoduje to MemoryError — lub w najlepszym przypadku wymusza na procesie przejście na dysk wymiany i pełzanie.
Strumieniowanie z ijson
ijson to strumieniowy parser JSON generujący elementy jeden po jednym z obiektu pliku. Iterujesz po elementach tablicy bez trzymania całego zbioru danych w pamięci — szczytowe użycie pamięci pozostaje proporcjonalne do jednego obiektu, nie rozmiaru pliku.
pip install ijson
import ijson
from decimal import Decimal
# zdarzenia.json ma strukturę: {"zdarzenia": [...miliony obiektów...]}
calkowity_przychod = Decimal("0")
liczba_logowan = 0
with open("zdarzenia.json", "rb") as f: # ijson wymaga trybu binarnego
for zdarzenie in ijson.items(f, "zdarzenia.item"):
if zdarzenie.get("typ") == "zakup":
calkowity_przychod += Decimal(str(zdarzenie["kwota_pln"]))
elif zdarzenie.get("typ") == "logowanie":
liczba_logowan += 1
print(f"Przychód: {calkowity_przychod:.2f} PLN | Logowania: {liczba_logowan}")
# Przetwarza plik 2 GB z ~30 MB szczytowego użycia pamięcijson.load() na ijson gdy plik przekracza około 50–100 MB. Poniżej tego progu json.load() jest prostszy i znacznie szybszy, ponieważ wewnętrznie używa parsera z rozszerzeniem C. Powyżej 100 MB oszczędności pamięci ze strumieniowania przeważają nad dodatkowym narzutem.NDJSON — jeden obiekt JSON na linię
NDJSON (Newline Delimited JSON, zwany też JSON Lines lub .jsonl) przechowuje jeden kompletny obiekt JSON na linię. Eksportery logów, konsumenci Kafka i potoki danych często produkują ten format, ponieważ każdą linię można niezależnie dołączać i odczytywać — nie trzeba parsować całego pliku, aby dodać rekord. Standardowa biblioteka obsługuje go bez żadnych dodatkowych zależności.
import json
from pathlib import Path
# Zapisz NDJSON — jedno zdarzenie na linię
zdarzenia = [
{"ts": "2024-05-01T10:00:00Z", "uzytkownik": "usr_9f3a2b", "akcja": "logowanie"},
{"ts": "2024-05-01T10:01:03Z", "uzytkownik": "usr_9f3a2b", "akcja": "zakup", "sku": "pro-plan"},
{"ts": "2024-05-01T10:15:42Z", "uzytkownik": "usr_4ab1d9", "akcja": "logowanie"},
]
with open("zdarzenia.ndjson", "w", encoding="utf-8") as f:
for zdarzenie in zdarzenia:
f.write(json.dumps(zdarzenie, ensure_ascii=False) + "\n")
# Odczytaj NDJSON — stała pamięć, niezależnie od rozmiaru pliku
liczba_zakupow = 0
with open("zdarzenia.ndjson", "r", encoding="utf-8") as f:
for linia in f:
linia = linia.strip()
if not linia: # pomiń puste linie
continue
zdarzenie = json.loads(linia)
if zdarzenie.get("akcja") == "zakup":
liczba_zakupow += 1
print(f"{zdarzenie['ts']} — {zdarzenie['uzytkownik']} kupił {zdarzenie['sku']}")Typowe błędy
Te cztery błędy widuję w prawie każdym przeglądzie kodu dotyczącym serializacji JSON — szczególnie od programistów przychodzących z JavaScript, gdzie JSON.stringify obsługuje kodowanie automatycznie.
Problem: print() na słowniku używa repr Pythona — wyjście pokazuje True/None (składnia Pythona), nie true/null (składnia JSON). To nie jest prawidłowy JSON.
Rozwiązanie: Zawsze używaj json.dumps(data, indent=4) do prawidłowego, czytelnego wyjścia JSON.
data = {"aktywny": True, "liczba": None}
print(data)
# {'aktywny': True, 'liczba': None}print(json.dumps(data, indent=4))
# {
# "aktywny": true,
# "liczba": null
# }Problem: Polskie litery i znaki specjalne (ą, ę, ó, ź, ż, ć itd.) są zamieniane na sekwencje \\uXXXX, czyniąc wyjście nieczytelnym.
Rozwiązanie: Przekaż ensure_ascii=False, aby zachować oryginalne znaki Unicode.
uzytkownik = {"miasto": "Kraków", "imie": "Piotr Kowalski"}
json.dumps(uzytkownik, indent=2)
# {"miasto": "Krak\u00f3w", "imie": "Piotr Kowalski"}json.dumps(uzytkownik, indent=2, ensure_ascii=False)
# {"miasto": "Kraków", "imie": "Piotr Kowalski"}Problem: json.dumps() zwraca ciąg; potrzebujesz osobnego wywołania f.write(), tworząc niepotrzebny pośredni ciąg.
Rozwiązanie: Użyj json.dump(data, f, indent=4) — zapisuje bezpośrednio do obiektu pliku.
with open("wyjscie.json", "w") as f:
f.write(json.dumps(data, indent=4))with open("wyjscie.json", "w", encoding="utf-8") as f:
json.dump(data, f, indent=4, ensure_ascii=False)Problem: pprint.pprint() używa składni Pythona (True, None, pojedyncze cudzysłowy), którą parsery JSON odrzucają.
Rozwiązanie: Użyj json.dumps(indent=4) do każdego wyjścia, które musi być parsowalne jako JSON.
import pprint
pprint.pprint({"dziala": True, "ostatni_blad": None})
# {'dziala': True, 'ostatni_blad': None}import json
print(json.dumps({"dziala": True, "ostatni_blad": None}, indent=4))
# {"dziala": true, "ostatni_blad": null}Porównanie metod — json.dumps, orjson, simplejson, rich
Używaj json.dumps() do codziennego formatowania i zapisu plików — obsługuje 95% przypadków bez żadnych zależności. Sięgaj po orjson przy serializacji w gorącej ścieżce lub gdy obiekty zawierają pola datetime i UUID. Używaj simplejson gdy potrzebujesz bezpośredniej kompatybilności ze stdlib z obsługą Decimal od razu. Zachowaj rich.print_json() i pprint wyłącznie do lokalnej inspekcji w terminalu — żadne nie produkuje wyjścia czytalnego maszynowo.
Często zadawane pytania
Jak ładnie wydrukować JSON w Pythonie?
Wywołaj json.dumps(data, indent=4). Parametr indent określa liczbę spacji na poziom zagnieżdżenia. Najpierw zaimportuj moduł json — jest dostarczany ze standardową biblioteką Pythona, nie jest wymagany pip install. Przekaż ensure_ascii=False, jeśli Twoje dane zawierają polskie litery, znaki akcentowane lub znaki CJK.
import json
uzytkownik = {"username": "pkowalski", "plan": "enterprise", "uprawnienia": ["odczyt", "zapis", "deploy"]}
print(json.dumps(uzytkownik, indent=4, ensure_ascii=False))Jaka jest różnica między json.dumps() a json.dump()?
json.dumps() (z "s") zwraca sformatowany ciąg w pamięci. json.dump() (bez "s") zapisuje bezpośrednio do obiektu pliku — przekaż otwarty uchwyt pliku jako drugi argument. Do zapisywania sformatowanego JSON na dysk idiomatyczny jest json.dump(data, f, indent=4) — unika tworzenia pośredniego ciągu.
# dumps → ciąg w pamięci
sformatowany = json.dumps(data, indent=4)
# dump → zapisz bezpośrednio do pliku
with open('wyjscie.json', 'w', encoding='utf-8') as f:
json.dump(data, f, indent=4)Dlaczego json.dumps() wyświetla \u00f3\u015b\u0144 zamiast rzeczywistego znaku?
Domyślnie ensure_ascii=True zamienia każdy znak spoza ASCII na sekwencję \uXXXX. Ustaw ensure_ascii=False, aby zachować oryginalne znaki Unicode. Jest to szczególnie ważne dla polskich nazw, adresów i wszelkich treści generowanych przez użytkowników zawierających polskie litery.
data = {"miasto": "Kraków", "pozdrowienie": "Łódź", "symbol": "żółw"}
# Domyślnie — ze znakami ucieczki
json.dumps(data, indent=4)
# {"miasto": "Krak\u00f3w", "pozdrowienie": "\u0141\u00f3d\u017a", ...}
# Czytelny
json.dumps(data, indent=4, ensure_ascii=False)
# {"miasto": "Kraków", "pozdrowienie": "Łódź", "symbol": "żółw"}Jak ładnie wydrukować ciąg JSON (nie słownik)?
Najpierw przetworz ciąg za pomocą json.loads(), a następnie sformatuj za pomocą json.dumps(). Oba wywołania można połączyć w jednej linii do szybkiej inspekcji w terminalu.
import json
surowy = '{"endpoint":"/api/v2/zamowienia","timeout":30,"ponow_probe":true}'
print(json.dumps(json.loads(surowy), indent=4))Czy mogę używać pprint do formatowania JSON w Pythonie?
pprint.pprint() produkuje reprezentację obiektów Pythona, nie prawidłowy JSON. Używa True/False/None (składnia Pythona) zamiast true/false/null (składnia JSON). Nigdy nie przekazuj wyjścia pprint do API ani parsera JSON — używaj json.dumps(indent=4) do wszystkiego, co musi być prawidłowym JSON.
import pprint, json
data = {"aktywny": True, "wynik": None}
pprint.pprint(data) # {'aktywny': True, 'wynik': None} ← nie JSON
json.dumps(data, indent=4) # {"aktywny": true, "wynik": null} ← prawidłowy JSONJak posortować klucze JSON alfabetycznie w Pythonie?
Dodaj sort_keys=True do json.dumps(). W wierszu poleceń użyj python -m json.tool --sort-keys data.json. Posortowane klucze sprawiają, że różnice JSON są czytelne i pomagają zauważyć zmienione wartości na pierwszy rzut oka.
import json
serwer = {"workers": 4, "host": "0.0.0.0", "port": 8080, "debug": False}
print(json.dumps(serwer, indent=4, sort_keys=True))
# {
# "debug": false,
# "host": "0.0.0.0",
# "port": 8080,
# "workers": 4
# }Python daje pełną kontrolę — własne serializatory, streaming, integracja z pipeline. Gdy wystarczy tylko sprawdzić lub udostępnić sformatowany fragment, Formater JSON od ToolDeck jest szybszą drogą: wklej JSON i uzyskaj wynik z wcięciami i podświetleniem bez konfiguracji środowiska.
Podobne narzędzia
Maria is a backend developer specialising in Python and API integration. She has broad experience with data pipelines, serialisation formats, and building reliable server-side services. She is an active member of the Python community and enjoys writing practical, example-driven guides that help developers solve real problems without unnecessary theory.
Dmitri is a DevOps engineer who relies on Python as his primary scripting and automation language. He builds internal tooling, CI/CD pipelines, and infrastructure automation scripts that run in production across distributed teams. He writes about the Python standard library, subprocess management, file processing, encoding utilities, and the practical shell-adjacent Python that DevOps engineers use every day.