Python e JSON: Guida completa alla manipolazione dati
Impara a lavorare con JSON in Python: parsing, serializzazione, validazione, file I/O e best practices. Include esempi pratici con json, jsonschema e pydantic.
Big JSON Team
• Technical WriterExpert in JSON data manipulation, API development, and web technologies. Passionate about creating tools that make developers' lives easier.
# Python e JSON: Guida completa alla manipolazione dati
Python è uno dei linguaggi più utilizzati per lavorare con JSON grazie alla sua semplicità e potenza. Questa guida ti insegnerà tutto ciò che devi sapere per manipolare JSON in Python in modo professionale.
Il modulo json di Python
Python include il modulo json nella libreria standard, che fornisce tutti gli strumenti necessari per lavorare con JSON.
import json
# Il modulo json è incluso di default in Python!
Parsing JSON (da stringa a oggetto Python)
json.loads() - Load String
import json
# Stringa JSON
json_string = '{"nome": "Marco", "età": 30, "città": "Milano"}'
# Converti in dizionario Python
dati = json.loads(json_string)
print(type(dati)) # <class 'dict'>
print(dati["nome"]) # Marco
print(dati["età"]) # 30
Gestione errori di parsing
import json
json_invalido = '{"nome": "Marco", "età": 30,}' # virgola finale!
try:
dati = json.loads(json_invalido)
except json.JSONDecodeError as e:
print(f"Errore di parsing: {e}")
print(f"Linea: {e.lineno}, Colonna: {e.colno}")
print(f"Messaggio: {e.msg}")
# Output:
# Errore di parsing: Expecting property name enclosed in double quotes: line 1 column 32 (char 31)
# Linea: 1, Colonna: 32
# Messaggio: Expecting property name enclosed in double quotes
Parsing di tipi JSON diversi
import json
# Oggetto
obj = json.loads('{"chiave": "valore"}')
print(type(obj)) # <class 'dict'>
# Array
arr = json.loads('["mela", "banana", "arancia"]')
print(type(arr)) # <class 'list'>
# Numero
num = json.loads('42')
print(type(num)) # <class 'int'>
# String
s = json.loads('"ciao"')
print(type(s)) # <class 'str'>
# Boolean
b = json.loads('true')
print(type(b)) # <class 'bool'>
# Null
n = json.loads('null')
print(type(n)) # <class 'NoneType'>
Serializzazione (da oggetto Python a JSON)
json.dumps() - Dump String
import json
# Dizionario Python
utente = {
"nome": "Marco",
"cognome": "Rossi",
"età": 30,
"città": "Milano",
"hobby": ["programmazione", "viaggi", "fotografia"]
}
# Converti in stringa JSON
json_string = json.dumps(utente)
print(json_string)
# {"nome": "Marco", "cognome": "Rossi", "età": 30, "città": "Milano", "hobby": ["programmazione", "viaggi", "fotografia"]}
Formattazione con indent
import json
utente = {
"nome": "Marco",
"età": 30,
"contatti": {
"email": "marco@example.com",
"telefono": "+39 02 1234 5678"
}
}
# JSON formattato con 2 spazi
json_formattato = json.dumps(utente, indent=2)
print(json_formattato)
# Output:
# {
# "nome": "Marco",
# "età": 30,
# "contatti": {
# "email": "marco@example.com",
# "telefono": "+39 02 1234 5678"
# }
# }
Ordinare le chiavi
import json
dati = {
"z_ultimo": 3,
"a_primo": 1,
"m_medio": 2
}
# Ordina le chiavi alfabeticamente
json_ordinato = json.dumps(dati, indent=2, sort_keys=True)
print(json_ordinato)
# Output:
# {
# "a_primo": 1,
# "m_medio": 2,
# "z_ultimo": 3
# }
Gestione caratteri Unicode
import json
dati = {
"città": "Milano",
"caffè": "Espresso",
"emoji": "👋 Ciao!"
}
# Senza ensure_ascii (consigliato per italiano)
json_unicode = json.dumps(dati, indent=2, ensure_ascii=False)
print(json_unicode)
# {
# "città": "Milano",
# "caffè": "Espresso",
# "emoji": "👋 Ciao!"
# }
# Con ensure_ascii (default)
json_ascii = json.dumps(dati, indent=2, ensure_ascii=True)
print(json_ascii)
# {
# "citt\u00e0": "Milano",
# "caff\u00e8": "Espresso",
# "emoji": "\ud83d\udc4b Ciao!"
# }
Lavorare con file JSON
json.load() - Leggere da file
import json
# Leggi file JSON
with open('utente.json', 'r', encoding='utf-8') as file:
dati = json.load(file)
print(dati)
json.dump() - Scrivere su file
import json
utente = {
"nome": "Marco",
"età": 30,
"città": "Milano"
}
# Scrivi file JSON
with open('utente.json', 'w', encoding='utf-8') as file:
json.dump(utente, file, indent=2, ensure_ascii=False)
Gestione errori I/O
import json
import os
def leggi_json_sicuro(file_path):
"""Leggi file JSON con gestione errori"""
try:
if not os.path.exists(file_path):
raise FileNotFoundError(f"File non trovato: {file_path}")
with open(file_path, 'r', encoding='utf-8') as file:
return json.load(file)
except FileNotFoundError as e:
print(f"Errore: {e}")
return None
except json.JSONDecodeError as e:
print(f"JSON non valido: {e}")
return None
except Exception as e:
print(f"Errore imprevisto: {e}")
return None
# Uso
dati = leggi_json_sicuro('config.json')
if dati:
print("File caricato con successo!")
Aggiornare file JSON
import json
def aggiorna_json(file_path, chiave, valore):
"""Aggiorna un valore in un file JSON"""
# Leggi file esistente
with open(file_path, 'r', encoding='utf-8') as file:
dati = json.load(file)
# Aggiorna valore
dati[chiave] = valore
# Scrivi file aggiornato
with open(file_path, 'w', encoding='utf-8') as file:
json.dump(dati, file, indent=2, ensure_ascii=False)
print(f"Aggiornato {chiave} = {valore}")
# Uso
aggiorna_json('config.json', 'versione', '2.0.0')
Mappatura tra tipi Python e JSON
Tabella di conversione
| Python | JSON | Note |
|--------|------|------|
| dict | object | {} |
| list, tuple | array | [] |
| str | string | "" |
| int, float | number | 42, 3.14 |
| True | true | minuscolo |
| False | false | minuscolo |
| None | null | |
Esempi di conversione
import json
# Python → JSON
python_data = {
"dizionario": {"a": 1},
"lista": [1, 2, 3],
"tupla": (4, 5, 6), # Diventa array
"stringa": "testo",
"intero": 42,
"float": 3.14,
"booleano_vero": True,
"booleano_falso": False,
"nullo": None
}
json_string = json.dumps(python_data, indent=2)
print(json_string)
# Output:
# {
# "dizionario": {"a": 1},
# "lista": [1, 2, 3],
# "tupla": [4, 5, 6],
# "stringa": "testo",
# "intero": 42,
# "float": 3.14,
# "booleano_vero": true,
# "booleano_falso": false,
# "nullo": null
# }
Serializzazione personalizzata
Custom JSONEncoder
import json
from datetime import datetime, date
from decimal import Decimal
class CustomJSONEncoder(json.JSONEncoder):
"""Encoder personalizzato per tipi non standard"""
def default(self, obj):
# Gestisci datetime
if isinstance(obj, datetime):
return obj.isoformat()
# Gestisci date
if isinstance(obj, date):
return obj.isoformat()
# Gestisci Decimal
if isinstance(obj, Decimal):
return float(obj)
# Gestisci set
if isinstance(obj, set):
return list(obj)
# Chiama il metodo default della classe padre
return super().default(obj)
# Uso
dati = {
"nome": "Marco",
"data_nascita": date(1994, 5, 15),
"ultimo_accesso": datetime(2026, 1, 26, 10, 30, 0),
"saldo": Decimal("1234.56"),
"tag": {"python", "json", "tutorial"}
}
json_string = json.dumps(dati, cls=CustomJSONEncoder, indent=2)
print(json_string)
# Output:
# {
# "nome": "Marco",
# "data_nascita": "1994-05-15",
# "ultimo_accesso": "2026-01-26T10:30:00",
# "saldo": 1234.56,
# "tag": ["python", "json", "tutorial"]
# }
Deserializzazione personalizzata
import json
from datetime import datetime
def custom_decoder(dct):
"""Decoder personalizzato"""
for key, value in dct.items():
# Converti stringhe ISO in datetime
if isinstance(value, str):
try:
dct[key] = datetime.fromisoformat(value)
except ValueError:
pass
return dct
# JSON con date
json_string = '''
{
"nome": "Marco",
"creato_il": "2026-01-26T10:30:00"
}
'''
# Parse con decoder personalizzato
dati = json.loads(json_string, object_hook=custom_decoder)
print(type(dati["creato_il"])) # <class 'datetime.datetime'>
print(dati["creato_il"].year) # 2026
Lavorare con API JSON
Richieste GET
import json
import requests
# GET request
response = requests.get('https://api.example.com/users/123')
# Parse JSON automatico
utente = response.json()
print(utente["nome"])
# Oppure manualmente
utente = json.loads(response.text)
Richieste POST
import requests
# Dati da inviare
nuovo_utente = {
"nome": "Marco",
"email": "marco@example.com",
"ruolo": "admin"
}
# POST con JSON
response = requests.post(
'https://api.example.com/users',
json=nuovo_utente, # Serializzato automaticamente
headers={'Content-Type': 'application/json'}
)
# Response
if response.status_code == 201:
utente_creato = response.json()
print(f"Utente creato con ID: {utente_creato['id']}")
Gestione errori API
import requests
import json
def chiamata_api_sicura(url):
"""Chiamata API con gestione errori"""
try:
response = requests.get(url, timeout=5)
response.raise_for_status() # Lancia eccezione per status 4xx/5xx
return response.json()
except requests.exceptions.Timeout:
print("Timeout della richiesta")
return None
except requests.exceptions.HTTPError as e:
print(f"Errore HTTP: {e}")
return None
except json.JSONDecodeError:
print("Response non è JSON valido")
return None
except Exception as e:
print(f"Errore imprevisto: {e}")
return None
# Uso
dati = chiamata_api_sicura('https://api.example.com/data')
Validazione JSON Schema
Con jsonschema
from jsonschema import validate, ValidationError
import json
# Schema
schema = {
"type": "object",
"properties": {
"nome": {"type": "string", "minLength": 1},
"età": {"type": "integer", "minimum": 0, "maximum": 150},
"email": {"type": "string", "format": "email"}
},
"required": ["nome", "età"]
}
# Dati validi
dati_validi = {
"nome": "Marco",
"età": 30,
"email": "marco@example.com"
}
# Validazione
try:
validate(instance=dati_validi, schema=schema)
print("✅ Dati validi!")
except ValidationError as e:
print(f"❌ Validazione fallita: {e.message}")
# Dati non validi
dati_invalidi = {
"nome": "", # Troppo corto
"età": 200 # Troppo grande
}
try:
validate(instance=dati_invalidi, schema=schema)
except ValidationError as e:
print(f"❌ Errore: {e.message}")
# Output: '' is too short
Pydantic per validazione avanzata
from pydantic import BaseModel, EmailStr, Field
from typing import List, Optional
from datetime import datetime
class Indirizzo(BaseModel):
via: str
città: str
cap: str = Field(..., regex=r'^\d{5}$')
class Utente(BaseModel):
id: int
nome: str = Field(..., min_length=1, max_length=100)
email: EmailStr
età: int = Field(..., ge=0, le=150)
ruoli: List[str] = []
indirizzo: Optional[Indirizzo] = None
creato_il: datetime
attivo: bool = True
# Dati JSON
json_data = '''
{
"id": 123,
"nome": "Marco Rossi",
"email": "marco@example.com",
"età": 30,
"ruoli": ["admin", "editor"],
"indirizzo": {
"via": "Via Roma 123",
"città": "Milano",
"cap": "20100"
},
"creato_il": "2026-01-26T10:30:00",
"attivo": true
}
'''
# Parse e valida
try:
utente = Utente.parse_raw(json_data)
print(f"✅ Utente valido: {utente.nome}")
print(f"Email: {utente.email}")
print(f"CAP: {utente.indirizzo.cap}")
# Converti di nuovo in JSON
json_output = utente.json(indent=2)
print(json_output)
except Exception as e:
print(f"❌ Validazione fallita: {e}")
JSON Lines (JSONL)
Leggere file JSONL
import json
# File con un oggetto JSON per riga
# file.jsonl:
# {"id": 1, "nome": "Marco"}
# {"id": 2, "nome": "Laura"}
# {"id": 3, "nome": "Paolo"}
def leggi_jsonl(file_path):
"""Leggi file JSON Lines"""
records = []
with open(file_path, 'r', encoding='utf-8') as file:
for line in file:
if line.strip(): # Ignora righe vuote
record = json.loads(line)
records.append(record)
return records
# Uso
utenti = leggi_jsonl('utenti.jsonl')
for utente in utenti:
print(utente["nome"])
Scrivere file JSONL
import json
def scrivi_jsonl(file_path, records):
"""Scrivi file JSON Lines"""
with open(file_path, 'w', encoding='utf-8') as file:
for record in records:
json_line = json.dumps(record, ensure_ascii=False)
file.write(json_line + '\n')
# Uso
utenti = [
{"id": 1, "nome": "Marco"},
{"id": 2, "nome": "Laura"},
{"id": 3, "nome": "Paolo"}
]
scrivi_jsonl('utenti.jsonl', utenti)
Performance e ottimizzazione
ujson - Parser più veloce
import ujson
# ujson è più veloce del modulo json standard
dati = ujson.loads('{"nome": "Marco", "età": 30}')
json_string = ujson.dumps(dati, indent=2)
# Benchmark
import json
import ujson
import time
json_string = '{"dati": [' + ','.join(['{"id": %d}' % i for i in range(10000)]) + ']}'
# Test json
start = time.time()
json.loads(json_string)
print(f"json: {time.time() - start:.4f}s")
# Test ujson
start = time.time()
ujson.loads(json_string)
print(f"ujson: {time.time() - start:.4f}s")
# ujson è tipicamente 2-3x più veloce
Streaming di JSON grande
import ijson
# Per file JSON molto grandi
with open('large_data.json', 'rb') as file:
# Parse incrementale
parser = ijson.items(file, 'utenti.item')
for utente in parser:
print(utente["nome"])
# Processa un utente alla volta
# Non carica tutto in memoria
Best practices
1. Usa context manager per file
# ✅ Corretto
with open('data.json', 'r') as file:
dati = json.load(file)
# ❌ Da evitare
file = open('data.json', 'r')
dati = json.load(file)
file.close() # Può essere dimenticato
2. Specifica encoding
# ✅ Corretto
with open('data.json', 'r', encoding='utf-8') as file:
dati = json.load(file)
# ❌ Problemi potenziali con caratteri speciali
with open('data.json', 'r') as file:
dati = json.load(file)
3. Gestisci sempre gli errori
import json
def parse_json_sicuro(json_string):
"""Parse JSON con gestione errori"""
try:
return json.loads(json_string)
except json.JSONDecodeError as e:
print(f"Errore parsing: {e}")
return None
except Exception as e:
print(f"Errore imprevisto: {e}")
return None
4. Usa ensure_ascii=False per testo non-ASCII
# ✅ Corretto per italiano
json.dumps(dati, ensure_ascii=False)
# ❌ Caratteri escaped
json.dumps(dati, ensure_ascii=True)
5. Formatta per leggibilità
# ✅ Formattato
json.dumps(dati, indent=2, ensure_ascii=False)
# ❌ Compatto (difficile da leggere)
json.dumps(dati)
Conclusione
Python offre strumenti potenti per lavorare con JSON:
Modulo standard:json.loads()/json.dumps()per stringhejson.load()/json.dump()per file
jsonschemaper validazionepydanticper modelli tipizzatiujsonper performanceijsonper streaming
- Gestisci sempre gli errori
- Usa
ensure_ascii=Falseper Unicode - Formatta con
indent - Valida con schema quando necessario
Con queste conoscenze, sei pronto a lavorare professionalmente con JSON in Python!
Articoli Correlati
File JSON spiegato: Struttura, sintassi e utilizzo pratico
Guida completa ai file JSON: impara la struttura, la sintassi, come creare, leggere e modificare file JSON. Include esempi pratici e best practices.
JavaScript e JSON: Guida completa a JSON.parse() e JSON.stringify()
Guida completa su JSON in JavaScript: parsing, serializzazione, gestione errori, localStorage, fetch API e best practices. Include esempi pratici e troubleshooting.
API JSON e servizi REST: Guida completa per sviluppatori
Guida completa alle API JSON e REST: metodi HTTP, autenticazione, best practices, esempi pratici con fetch e axios. Impara a creare e consumare API moderne.