← Torna al Blog

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 Team15 min di letturaprogramming
B

Big JSON Team

Technical Writer

Expert in JSON data manipulation, API development, and web technologies. Passionate about creating tools that make developers' lives easier.

15 min di lettura

# 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 stringhe
  • json.load() / json.dump() per file

Librerie avanzate:
  • jsonschema per validazione
  • pydantic per modelli tipizzati
  • ujson per performance
  • ijson per streaming

Best practices:
  • Gestisci sempre gli errori
  • Usa ensure_ascii=False per Unicode
  • Formatta con indent
  • Valida con schema quando necessario

Con queste conoscenze, sei pronto a lavorare professionalmente con JSON in Python!

Share:

Articoli Correlati

Read in English