JSON Formatter Python — Guida a json.dumps()

·Backend Developer·Revisionato daDmitri Volkov·Pubblicato

Usa il Formattatore e Abbellitore JSON gratuito direttamente nel tuo browser — nessuna installazione.

Prova Formattatore e Abbellitore JSON online →

Quando sto eseguendo il debug di un client API Python, la prima cosa a cui ricorro è python formattare json — una singola chiamata a json.dumps(data, indent=4) e un blob illeggibile su una sola riga diventa immediatamente navigabile. Il modulo integrato json di Python gestisce tutto ciò interamente nella libreria standard — nessuna installazione di terze parti richiesta. Se hai solo bisogno di un risultato rapido senza scrivere codice, il Formattatore JSON di ToolDeck lo fa istantaneamente. Questa guida copre ogni metodo pratico: json.dumps() con tutti i suoi parametri, pprint, orjson per la formattazione ad alte prestazioni, la CLI json.tool, e scenari reali come la formattazione delle risposte API e la lettura da disco — tutto con codice compatibile con Python 3.8+. Copre anche la serializzazione di tipi personalizzati come datetime e UUID, lo streaming di file da gigabyte con ijson, e la colorazione sintattica nel terminale con rich.

Punti Chiave
  • json.dumps(data, indent=4) è integrato nella stdlib di Python dalla versione 2.6 — nessuna installazione necessaria.
  • Passa ensure_ascii=False ogni volta che i tuoi dati contengono lettere accentate, caratteri CJK o emoji.
  • Per datetime, UUID o classi personalizzate usa il parametro default= o crea una sottoclasse di json.JSONEncoder.
  • separators=(',', ':') elimina tutti gli spazi — da usare per la trasmissione in rete o l'incorporamento negli URL.
  • orjson è 5–10× più veloce della stdlib e gestisce nativamente datetime e uuid.UUID.
  • pprint.pprint() produce sintassi Python (True/None), non JSON valido — non usare mai per file o risposte API.
  • Per file JSON superiori a 50 MB, fai lo streaming con ijson invece di json.load() per evitare MemoryError.

Cos'è la formattazione JSON leggibile?

La formattazione leggibile (pretty printing) trasforma una stringa JSON densa e minificata in un formato leggibile dall'uomo con indentazione coerente e interruzioni di riga. La trasformazione è puramente cosmetica: i dati sono identici, cambia solo la presentazione. Il modulo json di Python gestisce tutto ciò interamente nella libreria standard — niente da installare.

Before · json
After · json
{"id":"usr_9f3a2b","name":"Marco Rossi","roles":["admin","editor"],"prefs":{"theme":"dark","lang":"it"}}
{
    "id": "usr_9f3a2b",
    "name": "Marco Rossi",
    "roles": [
        "admin",
        "editor"
    ],
    "prefs": {
        "theme": "dark",
        "lang": "it"
    }
}

json.dumps() — Il metodo standard per formattare JSON

json.dumps() fa parte della libreria standard di Python dalla versione 2.6 — semplicemente import json, nessuna installazione necessaria. Serializza qualsiasi oggetto Python compatibile con JSON in una stringa formattata. Il parametro chiave è indent: impostalo a 4 (o 2) per ottenere un output leggibile.

Python 3.8+ — esempio minimale
import json

utente = {
    "id": "usr_9f3a2b",
    "name": "Marco Rossi",
    "roles": ["admin", "editor"],
    "prefs": {"theme": "dark", "lang": "it"}
}

print(json.dumps(utente, indent=4, ensure_ascii=False))
# Output:
# {
#     "id": "usr_9f3a2b",
#     "name": "Marco Rossi",
#     "roles": [
#         "admin",
#         "editor"
#     ],
#     "prefs": {
#         "theme": "dark",
#         "lang": "it"
#     }
# }

Per uso in produzione vorrai spesso sort_keys=True (output coerente tra le esecuzioni) e ensure_ascii=False (mantenere i caratteri non-ASCII leggibili):

Python 3.8+ — con sort_keys e ensure_ascii
import json

risposta_api = {
    "timestamp": "2024-05-01T10:30:00Z",
    "status": "success",
    "data": {
        "user_id": "usr_9f3a2b",
        "display_name": "Giulia Ferrari",
        "citta": "Milano",
        "score": 4892.5,
        "tags": ["python", "backend", "api"]
    }
}

print(json.dumps(risposta_api, indent=4, sort_keys=True, ensure_ascii=False))
# Output (chiavi ordinate, accenti preservati):
# {
#     "data": {
#         "citta": "Milano",
#         "display_name": "Giulia Ferrari",
#         "score": 4892.5,
#         "tags": ["api", "backend", "python"],
#         "user_id": "usr_9f3a2b"
#     },
#     "status": "success",
#     "timestamp": "2024-05-01T10:30:00Z"
# }
Nota:json.dumps() restituisce una stringa. Per scrivere JSON formattato direttamente in un file, usa json.dump(data, f, indent=4) (senza la s) — scrive in un oggetto file ed evita di creare una stringa intermedia in memoria.

Riferimento dei parametri di json.dumps()

Tutti i parametri sono opzionali tranne l'oggetto stesso. I valori di default producono JSON compatto e sicuro in ASCII — passa i parametri esplicitamente per un output leggibile dall'uomo.

Parametro
Tipo
Default
Descrizione
obj
any
Oggetto Python da serializzare in una stringa in formato JSON.
indent
int | str | None
None
Spazi per livello di indentazione. None = riga singola compatta, 0 = solo a capo, 4 = standard.
sort_keys
bool
False
Ordina le chiavi del dizionario alfabeticamente su tutti i livelli annidati.
ensure_ascii
bool
True
Escape dei caratteri non-ASCII in \uXXXX. Impostare False per preservare i caratteri Unicode originali.
separators
tuple | None
None
Coppia (sep_elemento, sep_chiave). Usare (",", ":") per l'output più compatto senza spazi.
default
callable | None
None
Chiamato per i tipi non serializzabili per default. Sollevare TypeError per rifiutare il valore.
allow_nan
bool
True
Serializza float("nan") e float("inf") come letterali JS. Impostare False per sollevare ValueError.

Output JSON compatto con il parametro separators

Per default json.dumps() separa gli elementi con ", " e le chiavi dai valori con ": ". Il parametro separators sovrascrive entrambi. Passare (',', ':') elimina tutti gli spazi per produrre il JSON valido più compatto possibile — utile per la trasmissione in rete, l'incorporamento negli URL o la memorizzazione di JSON in una colonna di database dove ogni byte conta.

Python 3.8+
import json

payload = {
    "endpoint": "/api/v2/events",
    "filters": {"status": "active", "limit": 100},
    "sort": "desc"
}

# Default — spazi dopo i separatori (leggibile)
output_normale = json.dumps(payload)
# {"endpoint": "/api/v2/events", "filters": {"status": "active", "limit": 100}, "sort": "desc"}
# len = 88

# Compatto — nessuno spazio
output_compatto = json.dumps(payload, separators=(',', ':'))
# {"endpoint":"/api/v2/events","filters":{"status":"active","limit":100},"sort":"desc"}
# len = 80  (9% più piccolo; il risparmio cresce con payload più grandi e profondamente annidati)

# Compatto + chiavi ordinate per chiavi di cache riproducibili o hash di contenuto
canonico = json.dumps(payload, separators=(',', ':'), sort_keys=True)
print(canonico)
# {"endpoint":"/api/v2/events","filters":{"limit":100,"status":"active"},"sort":"desc"}
Nota:Quando passi indent= insieme a separators=, l'argomento separators controlla solo i separatori inline — le interruzioni di riga e l'indentazione di indent vengono preservate. Per un output compatto su una sola riga, ometti indent (o passa None) e imposta separators=(',', ':').

Serializzare oggetti Python personalizzati con il parametro default

Il modulo standard json serializza dict, liste, stringhe, numeri, booleani e None — ma solleva un TypeError per qualsiasi altro tipo. I due colpevoli più comuni nel codice di produzione sono gli oggetti datetime e gli UUID.

Python 3.8+ — TypeError senza gestione personalizzata
import json
from datetime import datetime, timezone
import uuid

ordine = {
    "order_id": uuid.uuid4(),            # ❌ TypeError: UUID is not JSON serializable
    "placed_at": datetime.now(timezone.utc),  # ❌ TypeError: datetime is not JSON serializable
    "totale_eur": 142.50,
    "items": ["pro-subscription", "addon-storage"]
}

json.dumps(ordine)  # solleva TypeError

Approccio 1 — il parametro default=

Passa un callable a default=. json.dumps() lo chiama per qualsiasi oggetto che non riesce a gestire. Restituisci una rappresentazione serializzabile, oppure solleva TypeError per i tipi che non supporti esplicitamente — non ignorare mai silenziosamente i tipi sconosciuti.

Python 3.8+
import json
from datetime import datetime, timezone, date
import uuid
from decimal import Decimal

def json_default(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"Type {type(obj).__name__!r} is not JSON serializable")

ordine = {
    "order_id": uuid.uuid4(),
    "placed_at": datetime(2024, 5, 1, 10, 30, 0, tzinfo=timezone.utc),
    "totale_eur": Decimal("142.50"),
    "items": ["pro-subscription", "addon-storage"]
}

print(json.dumps(ordine, indent=4, default=json_default))
# {
#     "order_id": "a3f1c2d4-e5b6-7890-abcd-ef1234567890",
#     "placed_at": "2024-05-01T10:30:00+00:00",
#     "totale_eur": 142.5,
#     "items": ["pro-subscription", "addon-storage"]
# }

Approccio 2 — sottoclasse di json.JSONEncoder

Per la logica di codifica riutilizzabile condivisa tra più moduli, creare una sottoclasse di json.JSONEncoder è più pulito che passare una funzione default ovunque. Sovrascrivi il metodo default e chiama super().default(obj) come ultimo fallback — questo preserva il corretto comportamento di errore per i tipi non supportati.

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)  # solleva TypeError per i tipi sconosciuti

ordine = {
    "order_id": uuid.uuid4(),
    "placed_at": datetime(2024, 5, 1, 10, 30, 0, tzinfo=timezone.utc),
    "totale_eur": Decimal("142.50"),
}

# Passa la classe encoder tramite cls=
print(json.dumps(ordine, indent=4, cls=AppEncoder))
# Output identico all'approccio con default=
Nota:Chiama sempre super().default(obj) (o solleva TypeError esplicitamente) per i tipi non riconosciuti. Restituire silenziosamente str(obj) per tutto corromperà gli oggetti che avrebbero dovuto sollevare un errore — un bug difficile da rintracciare in produzione.

Decodifica inversa — object_hook

La codifica è solo metà della storia. Per ricostruire un oggetto Python personalizzato dal JSON, passa una funzione object_hook a json.loads() o json.load(). L'hook viene chiamato per ogni oggetto JSON decodificato (dict) e può restituire qualsiasi valore Python — fornendoti un ciclo completo di codifica ↔ decodifica.

Python 3.8+
import json
from datetime import datetime
from dataclasses import dataclass

@dataclass
class Event:
    name: str
    occurred_at: datetime
    user_id: str

def encode_event(obj):
    if isinstance(obj, Event):
        return {
            "__type__": "Event",
            "name": obj.name,
            "occurred_at": obj.occurred_at.isoformat(),
            "user_id": obj.user_id,
        }
    raise TypeError(f"Cannot serialize {type(obj)}")

def decode_event(d):
    if d.get("__type__") == "Event":
        return Event(
            name=d["name"],
            occurred_at=datetime.fromisoformat(d["occurred_at"]),
            user_id=d["user_id"],
        )
    return d

# Codifica
event = Event("login", datetime(2024, 5, 1, 10, 30), "usr_9f3a2b")
json_str = json.dumps(event, default=encode_event, indent=4)

# Decodifica in un'istanza Event
restored = json.loads(json_str, object_hook=decode_event)
print(type(restored))           # <class 'Event'>
print(restored.occurred_at)     # 2024-05-01 10:30:00
Nota:L'object_hook viene chiamato per ogni dict annidato nel documento — non solo al livello superiore. Includi un campo discriminatore (come "__type__") in modo che l'hook possa distinguere i tuoi oggetti personalizzati dai dict semplici che devono rimanere tali.

pprint — Il modulo alternativo (e quando non usarlo)

Il modulo pprint di Python (pretty printer) formatta le strutture dati Python per la leggibilità nel terminale. Funziona su oggetti Python analizzati, non su stringhe JSON — e il suo output usa la sintassi Python, non la sintassi 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 — repr Python valido, NON JSON valido
pprint.pprint(data, sort_dicts=False)
# {'sensor_id': 's-441',
#  'readings': [23.1, 23.4, 22.9],
#  'unit': 'celsius',
#  'active': True}        ← Python True, non JSON true

# json.dumps — JSON valido
print(json.dumps(data, indent=4))
# {
#     "sensor_id": "s-441",
#     "readings": [23.1, 23.4, 22.9],
#     "unit": "celsius",
#     "active": true      ← JSON valido
# }
Attenzione:Non inviare mai l'output di pprint a un endpoint API o scriverlo in un file .json — farà fallire qualsiasi parser JSON che si aspetti la sintassi standard. Usa json.dumps(indent=4) per qualsiasi output che deve essere JSON valido.

Quando pprint ha senso: ispezione rapida nel REPL o nel log di debug, specialmente quando l'oggetto contiene tipi non serializzabili in JSON (set, istanze di classi personalizzate, dataclass prima della conversione).

Come formattare una risposta JSON da Requests

Lo scenario reale più comune: hai un file JSON su disco o una risposta HTTP da un'API, e vuoi formattarlo per il debug o il logging. Entrambi i casi usano lo stesso approccio — analizza in un dict Python, poi formatta con json.dumps().

Lettura da un file

Python 3.8+
import json

try:
    with open("config.json", "r", encoding="utf-8") as f:
        data = json.load(f)

    # Stampa nella console
    print(json.dumps(data, indent=4, ensure_ascii=False))

    # Oppure scrivi la versione formattata su disco
    with open("config.formattato.json", "w", encoding="utf-8") as f:
        json.dump(data, f, indent=4, ensure_ascii=False)

except json.JSONDecodeError as e:
    print(f"JSON non valido: {e}")
except FileNotFoundError:
    print(f"File non trovato: config.json")

Formattazione di una risposta API

Python 3.8+ (richiede: pip install requests)
import json, requests
from requests.exceptions import HTTPError, ConnectionError, Timeout

def stampa_api(url: str) -> None:
    try:
        resp = requests.get(url, timeout=10)
        resp.raise_for_status()
        print(json.dumps(resp.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"Errore di rete: {e}")
    except json.JSONDecodeError:
        print(f"Il corpo della risposta non è JSON:\n{resp.text[:500]}")

stampa_api("https://api.github.com/repos/python/cpython")
Nota:response.json() analizza già il corpo della risposta — non è necessario chiamare json.loads() separatamente. Aggiungi sempre raise_for_status() prima di accedere a .json() per intercettare gli errori 4xx/5xx prima che causino un confuso errore di parsing.

Formattazione da riga di comando

Python viene fornito con json.tool, un modulo CLI per formattare JSON direttamente dal terminale — nessuno script Python necessario. Disponibile su qualsiasi macchina con Python installato.

bash
# Formattare un file locale
python -m json.tool config.json

# Inviare la risposta API attraverso il formattatore
curl -s https://api.github.com/users/gvanrossum | python -m json.tool

# Formattare da stdin
echo '{"service":"api-gateway","version":"2.1.0","healthy":true}' | python -m json.tool

# Ordinare le chiavi alfabeticamente
python -m json.tool --sort-keys data.json

# Indentazione personalizzata (Python 3.9+)
python -m json.tool --indent 2 data.json
Nota:Python 3.9 ha aggiunto i flag --indent e --no-indent. Per un filtraggio JSON più potente nel terminale, considera jq — ma python -m json.toolcopre il caso d'uso della formattazione senza dipendenze aggiuntive.

Se non sei affatto nel terminale — incollando una risposta Postman o un file di log — il Formattatore JSON di ToolDeck ti permette di incollare, formattare e copiare in un solo passaggio con evidenziazione della sintassi e validazione integrate.

Librerie alternative: orjson e rich

orjson — 5–10× più veloce con supporto nativo dei tipi

Il modulo standard json è abbastanza veloce per la maggior parte dei casi, ma se stai serializzando migliaia di oggetti al secondo — pipeline di logging, API ad alto throughput, grandi esportazioni di dati — orjson è 5–10× più veloce. Gestisce anche nativamente tipi che la libreria standard non riesce a serializzare senza una funzione default personalizzata: datetime, uuid.UUID, array numpy e dataclass.

bash — installazione
pip install orjson
Python 3.8+
import orjson
from datetime import datetime, timezone
import uuid

event = {
    "event_id": uuid.uuid4(),                  # nessun str() necessario — orjson gestisce UUID
    "timestamp": datetime.now(timezone.utc),   # nessun isoformat() necessario
    "service": "auth-service",
    "level": "INFO",
    "payload": {
        "user_id": "usr_9f3a2b",
        "action": "login",
        "ip": "192.168.1.42",
        "latency_ms": 34
    }
}

# orjson.dumps restituisce bytes; .decode() converte in str
print(orjson.dumps(event, option=orjson.OPT_INDENT_2).decode())
# {
#   "event_id": "a3f1c2d4-e5b6-7890-abcd-ef1234567890",
#   "timestamp": "2024-05-01T10:30:00+00:00",
#   "service": "auth-service",
#   ...
# }

Due cose da sapere: orjson.dumps() restituisce bytes, non una stringa — chiama .decode() se hai bisogno di una stringa. Supporta solo l'indentazione a 2 spazi tramite OPT_INDENT_2; per output a 4 spazi usa il standard json.dumps(indent=4).

rich — Colorazione sintattica nel terminale

Se ispezioni regolarmente JSON in un terminale o REPL, rich visualizza output con codice colore e colorazione sintattica che rende le strutture profondamente annidate leggibili a colpo d'occhio. Chiavi, stringhe, numeri e booleani hanno ciascuno un colore distinto — molto più facile da analizzare di un muro di testo monocromatico. È uno strumento solo per il debug, non per la serializzazione in produzione.

bash — installazione
pip install rich
Python 3.8+
from rich import print_json
import json

# print_json() accetta una stringa JSON
raw = '{"event":"login","user_id":"usr_9f3a2b","timestamp":"2024-05-01T10:30:00Z","success":true,"meta":{"ip":"192.168.1.42","attempts":1}}'
print_json(raw)

# Per formattare un dict Python, convertilo prima in stringa
data = {
    "status": "success",
    "count": 42,
    "tags": ["python", "api", "backend"]
}
print_json(json.dumps(data))
Attenzione:rich.print_json() emette codici di escape ANSI per il colore del terminale — non catturare mai questo output e scriverlo in un file .json o inviarlo come risposta API. Usa json.dumps(indent=4) per qualsiasi output leggibile dalla macchina.

simplejson — Sostituto compatibile con la stdlib

simplejson è la libreria che è diventata il modulo standard json di Python — è ancora mantenuta indipendentemente e rimane avanti rispetto alla stdlib su funzionalità minori. È un vero sostituto drop-in: cambia l'import e il resto del codice rimane invariato. Utile quando hai bisogno del supporto Decimal senza un encoder personalizzato, o quando hai ambienti Python più vecchi.

bash — installazione
pip install simplejson
Python 3.8+
import simplejson as json  # API identica alla stdlib
from decimal import Decimal

ordine = {
    "item": "Abbonamento API Roma",
    "price": Decimal("49.99"),   # stdlib json solleverebbe TypeError qui
    "quantity": 3,
}

# simplejson serializza Decimal nativamente — nessun default= necessario
print(json.dumps(ordine, indent=4, use_decimal=True))
# {
#     "item": "Abbonamento API Roma",
#     "price": 49.99,
#     "quantity": 3
# }
Nota:Per le pure prestazioni, orjson è la scelta migliore. Usa simplejson quando hai bisogno della serializzazione nativa di Decimal senza scrivere un encoder personalizzato, o quando mantieni una codebase che lo usa già.

Elaborazione di file JSON di grandi dimensioni senza esaurire la memoria

json.load() legge l'intero file in memoria prima di poter accedere a un singolo campo. Su un file con milioni di record o un payload superiore a un gigabyte, questo causa un MemoryError — o nel migliore dei casi forza il processo a fare swap su disco e procedere molto lentamente.

Streaming con ijson

ijsonè un parser JSON in streaming che genera elementi uno alla volta da un oggetto file. Iteri sugli elementi dell'array senza mai tenere l'intero dataset in memoria — il picco di memoria rimane proporzionale a un singolo oggetto, non alla dimensione del file.

bash — installazione
pip install ijson
Python 3.8+
import ijson
from decimal import Decimal

# events.json struttura: {"events": [...milioni di oggetti...]}
ricavo_totale = Decimal("0")
contatore_login = 0

with open("events.json", "rb") as f:   # ijson richiede la modalità binaria
    for event in ijson.items(f, "events.item"):
        if event.get("type") == "purchase":
            ricavo_totale += Decimal(str(event["amount_eur"]))
        elif event.get("type") == "login":
            contatore_login += 1

print(f"Ricavo: {ricavo_totale:.2f} EUR  |  Login: {contatore_login}")
# Elabora un file da 2 GB con ~30 MB di picco di utilizzo della memoria
Nota:Passa da json.load() a ijson quando il tuo file supera circa 50–100 MB. Al di sotto di quella soglia json.load() è più semplice e significativamente più veloce perché usa internamente un parser con estensione C. Al di sopra di 100 MB, il risparmio di memoria dallo streaming supera il costo aggiuntivo.

NDJSON — un oggetto JSON per riga

NDJSON (Newline Delimited JSON, anche chiamato JSON Lines o .jsonl) memorizza un oggetto JSON completo per riga. Gli esportatori di log, i consumer Kafka e le pipeline di dati producono frequentemente questo formato perché ogni riga può essere aggiunta e letta in modo indipendente. La libreria standard lo gestisce senza dipendenze aggiuntive.

Python 3.8+
import json
from pathlib import Path

# Scrivere NDJSON — un evento per riga
events = [
    {"ts": "2024-05-01T10:00:00Z", "user": "usr_9f3a2b", "action": "login"},
    {"ts": "2024-05-01T10:01:03Z", "user": "usr_9f3a2b", "action": "purchase", "sku": "pro-plan"},
    {"ts": "2024-05-01T10:15:42Z", "user": "usr_4ab1d9", "action": "login"},
]

with open("events.ndjson", "w", encoding="utf-8") as f:
    for event in events:
        f.write(json.dumps(event, ensure_ascii=False) + "\n")

# Leggere NDJSON — memoria costante, indipendentemente dalla dimensione del file
contatore_acquisti = 0
with open("events.ndjson", "r", encoding="utf-8") as f:
    for riga in f:
        riga = riga.strip()
        if not riga:           # salta le righe vuote
            continue
        event = json.loads(riga)
        if event.get("action") == "purchase":
            contatore_acquisti += 1
            print(f"{event['ts']} — {event['user']} ha acquistato {event['sku']}")

Errori Comuni

Ho visto questi quattro errori in quasi ogni code review che riguarda la serializzazione JSON — specialmente da sviluppatori che arrivano da JavaScript dove JSON.stringify gestisce la codifica automaticamente.

Usare print(data) invece di json.dumps()

Problema: print() su un dict usa il repr Python — l'output mostra True/None (sintassi Python), non true/null (sintassi JSON). Non è JSON valido.

Soluzione: Usa sempre json.dumps(data, indent=4) per un output JSON valido e leggibile.

Before · Python
After · Python
data = {"active": True, "count": None}
print(data)
# {'active': True, 'count': None}
print(json.dumps(data, indent=4))
# {
#     "active": true,
#     "count": null
# }
Dimenticare ensure_ascii=False con testo non-ASCII

Problema: I caratteri speciali (lettere accentate, CJK, emoji) vengono trasformati in sequenze \\uXXXX, rendendo l'output illeggibile.

Soluzione: Passa ensure_ascii=False per preservare i caratteri Unicode originali.

Before · Python
After · Python
user = {"name": "Giulia Ferrari", "citta": "città"}
json.dumps(user, indent=2)
# {"name": "Giulia Ferrari", "citta": "citt\u00e0"}
json.dumps(user, indent=2, ensure_ascii=False)
# {"name": "Giulia Ferrari", "citta": "città"}
Usare json.dumps() per scrivere in un file

Problema: json.dumps() restituisce una stringa; poi hai bisogno di una chiamata f.write() separata, creando una stringa intermedia non necessaria.

Soluzione: Usa json.dump(data, f, indent=4) — scrive direttamente nell'oggetto file.

Before · Python
After · Python
with open("out.json", "w") as f:
    f.write(json.dumps(data, indent=4))
with open("out.json", "w", encoding="utf-8") as f:
    json.dump(data, f, indent=4, ensure_ascii=False)
Formattare con pprint aspettandosi JSON valido

Problema: pprint.pprint() usa la sintassi Python (True, None, virgolette singole) che i parser JSON rifiutano.

Soluzione: Usa json.dumps(indent=4) per qualsiasi output che deve essere analizzabile come JSON.

Before · Python
After · Python
import pprint
pprint.pprint({"running": True, "last_error": None})
# {'running': True, 'last_error': None}
import json
print(json.dumps({"running": True, "last_error": None}, indent=4))
# {"running": true, "last_error": null}

Confronto dei metodi — json.dumps, orjson, simplejson, rich

Usa json.dumps() per la formattazione quotidiana e la scrittura di file — copre il 95% dei casi senza dipendenze. Ricorri a orjson quando serializzi in un percorso critico o quando i tuoi oggetti includono campi datetime e UUID. Usa simplejson quando hai bisogno di compatibilità drop-in con la stdlib e supporto Decimal pronto all'uso. Riserva rich.print_json() e pprint strettamente per l'ispezione locale nel terminale — nessuno dei due produce output leggibile dalla macchina.

Metodo
Output
JSON Valido
Velocità
Non-ASCII
Tipi Custom
Installazione
json.dumps(indent=4)
Stringa
Standard
ensure_ascii=False
default= / JSONEncoder
Integrato
json.dump(f, indent=4)
File
Standard
ensure_ascii=False
default= / JSONEncoder
Integrato
pprint.pprint()
repr Python
Standard
Nativo
✅ (qualsiasi repr)
Integrato
orjson.dumps(OPT_INDENT_2)
Bytes
5–10× più veloce
Nativo
datetime, UUID, numpy
pip install orjson
python -m json.tool
stdout CLI
Standard
Integrato
simplejson.dumps()
Stringa
~1.5× più veloce
ensure_ascii=False
Decimal nativamente
pip install simplejson
rich.print_json()
Solo terminale
✅ (input)
Standard
pip install rich

Domande Frequenti

Come si visualizza il JSON in modo leggibile in Python?

Chiama json.dumps(data, indent=4). Il parametro indent imposta il numero di spazi per livello di annidamento. Importa prima il modulo json — è incluso nella libreria standard di Python, nessun pip install necessario. Passa ensure_ascii=False se i tuoi dati contengono lettere accentate, caratteri CJK o emoji.

python
import json

utente = {"username": "mrossi", "piano": "enterprise", "permessi": ["lettura", "scrittura", "deploy"]}
print(json.dumps(utente, indent=4, ensure_ascii=False))

Qual è la differenza tra json.dumps() e json.dump()?

json.dumps() (con la "s") restituisce una stringa formattata in memoria. json.dump() (senza "s") scrive direttamente in un oggetto file — passa l'handle del file aperto come secondo argomento. Per scrivere JSON formattato su disco, json.dump(data, f, indent=4) è idiomatico e evita di creare una stringa intermedia.

python
# dumps → stringa in memoria
formattato = json.dumps(data, indent=4)

# dump → scrittura diretta nel file
with open('output.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, indent=4)

Perché json.dumps() mostra \u00e0\u00e8\u00ec invece dei caratteri reali?

Per default ensure_ascii=True fa l'escape di ogni carattere non-ASCII in una sequenza \uXXXX. Imposta ensure_ascii=False per preservare i caratteri Unicode originali. Questo è particolarmente importante per nomi, indirizzi e qualsiasi contenuto generato dagli utenti in italiano o altre lingue non latine.

python
data = {"citta": "città", "bevanda": "perché", "parola": "è"}

# Default — con escape
json.dumps(data, indent=4)
# {"citta": "citt\u00e0", "bevanda": "perch\u00e9", ...}

# Leggibile
json.dumps(data, indent=4, ensure_ascii=False)
# {"citta": "città", "bevanda": "perché", "parola": "è"}

Come si formatta una stringa JSON (non un dict)?

Prima analizza la stringa con json.loads(), poi formatta con json.dumps(). Le due chiamate possono essere concatenate in una riga per un'ispezione rapida nel terminale.

python
import json

raw = '{"endpoint":"/api/v2/utenti","timeout":30,"riprova":true}'
print(json.dumps(json.loads(raw), indent=4))

Posso usare pprint per formattare JSON in Python?

pprint.pprint() produce una rappresentazione degli oggetti Python, non JSON valido. Usa True/False/None (sintassi Python) invece di true/false/null (sintassi JSON). Non passare mai l'output di pprint a un'API o un parser JSON — usa json.dumps(indent=4) per tutto ciò che deve essere JSON valido.

python
import pprint, json

data = {"attivo": True, "punteggio": None}

pprint.pprint(data)     # {'attivo': True, 'punteggio': None}  ← non è JSON
json.dumps(data, indent=4)  # {"attivo": true, "punteggio": null}  ← JSON valido

Come si ordinano le chiavi JSON alfabeticamente in Python?

Aggiungi sort_keys=True a json.dumps(). Da riga di comando, usa python -m json.tool --sort-keys data.json. Le chiavi ordinate rendono i diff JSON leggibili e aiutano a individuare i valori cambiati a colpo d'occhio.

python
import json

server = {"workers": 4, "host": "0.0.0.0", "port": 8080, "debug": False}
print(json.dumps(server, indent=4, sort_keys=True))
# {
#     "debug": false,
#     "host": "0.0.0.0",
#     "port": 8080,
#     "workers": 4
# }

Python ti dà pieno controllo — serializzatori personalizzati, streaming, integrazione pipeline. Quando hai solo bisogno di ispezionare o condividere uno snippet formattato, il Formattatore JSON di ToolDeck è il percorso più veloce: incolla il tuo JSON e ottieni un risultato indentato ed evidenziato senza configurare alcun ambiente.

Strumenti Correlati

Disponibile anche in: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 VolkovRevisore tecnico

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.