JSON Formatter Python — Poradnik json.dumps()

·Backend Developer·Sprawdzono przezDmitri Volkov·Opublikowano

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+.

Kluczowe wnioski
  • json.dumps(data, indent=4) jest wbudowane w stdlib Pythona od wersji 2.6 — nie wymaga instalacji.
  • Przekaż ensure_ascii=False gdy dane zawierają polskie litery, znaki akcentowane, znaki CJK lub emoji.
  • Dla datetime, UUID lub klas niestandardowych użyj parametru default= lub dziedzicz po json.JSONEncoder.
  • separators=(',', ':') usuwa wszystkie spacje — używaj do przesyłania sieciowego lub osadzania w URL.
  • orjson jest 5–10× szybszy niż stdlib i natywnie obsługuje datetime i uuid.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 ijson zamiast json.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.

Before · json
After · json
{"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.

Python 3.8+ — minimalny przykład
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):

Python 3.8+ — z sort_keys i ensure_ascii
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"
# }
Uwaga: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.

Parametr
Typ
Domyślny
Opis
obj
any
Obiekt Python do serializacji do ciągu w formacie JSON.
indent
int | str | None
None
Spacje na poziom wcięcia. None = kompaktowa jedna linia, 0 = tylko znaki nowej linii, 4 = standard.
sort_keys
bool
False
Sortuje klucze słownika alfabetycznie na wszystkich zagnieżdżonych poziomach.
ensure_ascii
bool
True
Zamienia znaki spoza ASCII na sekwencje \uXXXX. Ustaw False, aby zachować znaki Unicode.
separators
tuple | None
None
Para (sep_elementów, sep_kluczy). Użyj (",", ":") dla najbardziej kompaktowego wyjścia bez spacji.
default
callable | None
None
Wywoływane dla typów nieserializowalnych domyślnie. Rzuć TypeError, aby odrzucić wartość.
allow_nan
bool
True
Serializuje float("nan") i float("inf") jako literały JS. Ustaw False, aby rzucić ValueError.

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.

Python 3.8+
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"}
Uwaga:Gdy przekazujesz 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.

Python 3.8+ — TypeError bez niestandardowej obsługi
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 TypeError

Podejś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.

Python 3.8+
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.

Python 3.8+
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=
Uwaga:Zawsze wywołuj 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.

Python 3.8+
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:00
Uwaga:object_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.

Python 3.8+
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
# }
Ostrzeżenie:Nigdy nie wysyłaj wyjścia 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

Python 3.8+
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

Python 3.8+ (wymaga: pip install requests)
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")
Uwaga: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.

bash
# 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
Uwaga:Python 3.9 dodał flagi --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.

bash — instalacja
pip install orjson
Python 3.8+
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.

bash — instalacja
pip install rich
Python 3.8+
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))
Ostrzeżenie: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.

bash — instalacja
pip install simplejson
Python 3.8+
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
# }
Uwaga:Dla czystej wydajności 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.

bash — instalacja
pip install ijson
Python 3.8+
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ęci
Uwaga:Przejdź z json.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.

Python 3.8+
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.

Używanie print(data) zamiast json.dumps()

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.

Before · Python
After · Python
data = {"aktywny": True, "liczba": None}
print(data)
# {'aktywny': True, 'liczba': None}
print(json.dumps(data, indent=4))
# {
#     "aktywny": true,
#     "liczba": null
# }
Zapomnienie o ensure_ascii=False przy tekście z polskimi znakami

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.

Before · Python
After · Python
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"}
Używanie json.dumps() do zapisu do pliku

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.

Before · Python
After · Python
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)
Ładne drukowanie z pprint z oczekiwaniem prawidłowego JSON

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.

Before · Python
After · Python
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.

Metoda
Wyjście
Prawidłowy JSON
Szybkość
Non-ASCII
Typy niestandardowe
Instalacja
json.dumps(indent=4)
Ciąg
Standardowa
ensure_ascii=False
default= / JSONEncoder
Wbudowana
json.dump(f, indent=4)
Plik
Standardowa
ensure_ascii=False
default= / JSONEncoder
Wbudowana
pprint.pprint()
Python repr
Standardowa
Natywny
✅ (dowolny repr)
Wbudowana
orjson.dumps(OPT_INDENT_2)
Bajty
5–10× szybszy
Natywny
datetime, UUID, numpy
pip install orjson
python -m json.tool
CLI stdout
Standardowa
Wbudowana
simplejson.dumps()
Ciąg
~1.5× szybszy
ensure_ascii=False
Decimal natywnie
pip install simplejson
rich.print_json()
Tylko terminal
✅ (wejście)
Standardowa
pip install rich

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.

python
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.

python
# 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.

python
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.

python
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.

python
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 JSON

Jak 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.

python
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

Dostępne również w:GoJavaScriptBash
MS
Maria SantosBackend Developer

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.

DV
Dmitri VolkovRecenzent techniczny

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.