

Bild vom Autor
# Einführung
Arbeiten mit JSON in Python ist oft eine Herausforderung. Das Grundlegende json.hundreds() bringt dich nur so weit.
API-Antworten, Konfigurationsdateien und Datenexporte enthalten häufig JSON, das chaotisch oder schlecht strukturiert ist. Sie müssen verschachtelte Objekte reduzieren und Werte ohne sie sicher extrahieren Schlüsselfehler Ausnahmen, mehrere JSON-Dateien zusammenführen oder zwischen JSON und anderen Formaten konvertieren. Diese Aufgaben fallen beim Internet Scraping, der API-Integration und der Datenverarbeitung ständig an. Dieser Artikel führt Sie durch fünf praktische Funktionen zur Handhabung gängiger JSON-Parsing- und -Verarbeitungsaufgaben.
Den Code für diese Funktionen finden Sie unter GitHub.
# 1. Verschachtelte Werte sicher extrahieren
JSON-Objekte sind oft mehrere Ebenen tief verschachtelt. Der Zugriff auf tief verschachtelte Werte mit Klammernotation wird schnell zu einer Herausforderung. Sollte ein Schlüssel fehlen, erhalten Sie einen Schlüsselfehler.
Hier ist eine Funktion, mit der Sie mithilfe der Punktnotation auf verschachtelte Werte zugreifen können, mit einem Fallback für fehlende Schlüssel:
def get_nested_value(information, path, default=None):
"""
Safely extract nested values from JSON utilizing dot notation.
Args:
information: Dictionary or JSON object
path: Dot-separated string like "person.profile.e-mail"
default: Worth to return if path does not exist
Returns:
The worth on the path, or default if not discovered
"""
keys = path.cut up('.')
present = information
for key in keys:
if isinstance(present, dict):
present = present.get(key)
if present is None:
return default
elif isinstance(present, checklist):
strive:
index = int(key)
present = present(index)
besides (ValueError, IndexError):
return default
else:
return default
return present
Testen wir es mit einer komplexen verschachtelten Struktur:
# Pattern JSON information
user_data = {
"person": {
"id": 123,
"profile": {
"title": "Allie",
"e-mail": "allie@instance.com",
"settings": {
"theme": "darkish",
"notifications": True
}
},
"posts": (
{"id": 1, "title": "First Publish"},
{"id": 2, "title": "Second Publish"}
)
}
}
# Extract values
e-mail = get_nested_value(user_data, "person.profile.e-mail")
theme = get_nested_value(user_data, "person.profile.settings.theme")
first_post = get_nested_value(user_data, "person.posts.0.title")
lacking = get_nested_value(user_data, "person.profile.age", default=25)
print(f"Electronic mail: {e-mail}")
print(f"Theme: {theme}")
print(f"First put up: {first_post}")
print(f"Age (default): {lacking}")
Ausgabe:
Electronic mail: allie@instance.com
Theme: darkish
First put up: First Publish
Age (default): 25
Die Funktion teilt die Pfadzeichenfolge in Punkte auf und durchläuft die Datenstruktur Schlüssel für Schlüssel. Auf jeder Ebene wird geprüft, ob der aktuelle Wert ein Wörterbuch oder eine Liste ist. Für Wörterbücher verwendet es .get(key)was zurückkommt None für fehlende Schlüssel, anstatt einen Fehler auszulösen. Bei Hear wird versucht, den Schlüssel in einen ganzzahligen Index umzuwandeln.
Der default Der Parameter bietet einen Fallback, wenn ein Teil des Pfads nicht vorhanden ist. Dies verhindert, dass Ihr Code abstürzt, wenn Sie unvollständige oder inkonsistente JSON-Daten von APIs verarbeiten.
Dieses Muster ist besonders nützlich bei der Verarbeitung von API-Antworten, bei denen einige Felder non-compulsory sind oder nur unter bestimmten Bedingungen vorhanden sind.
# 2. Reduzieren von verschachteltem JSON in einstufige Wörterbücher
Modelle für maschinelles Lernen, CSV-Exporte und Datenbankeinfügungen erfordern häufig flache Datenstrukturen. Aber API-Antworten und Konfigurationsdateien verwenden verschachteltes JSON. Das Konvertieren verschachtelter Objekte in flache Schlüssel-Wert-Paare ist eine häufige Aufgabe.
Hier ist eine Funktion, die verschachteltes JSON mit anpassbaren Trennzeichen flacher macht:
def flatten_json(information, parent_key='', separator="_"):
"""
Flatten nested JSON right into a single-level dictionary.
Args:
information: Nested dictionary or JSON object
parent_key: Prefix for keys (utilized in recursion)
separator: String to affix nested keys
Returns:
Flattened dictionary with concatenated keys
"""
gadgets = ()
if isinstance(information, dict):
for key, worth in information.gadgets():
new_key = f"{parent_key}{separator}{key}" if parent_key else key
if isinstance(worth, dict):
# Recursively flatten nested dicts
gadgets.lengthen(flatten_json(worth, new_key, separator).gadgets())
elif isinstance(worth, checklist):
# Flatten lists with listed keys
for i, merchandise in enumerate(worth):
list_key = f"{new_key}{separator}{i}"
if isinstance(merchandise, (dict, checklist)):
gadgets.lengthen(flatten_json(merchandise, list_key, separator).gadgets())
else:
gadgets.append((list_key, merchandise))
else:
gadgets.append((new_key, worth))
else:
gadgets.append((parent_key, information))
return dict(gadgets)
Lassen Sie uns nun eine komplexe verschachtelte Struktur reduzieren:
# Complicated nested JSON
product_data = {
"product": {
"id": 456,
"title": "Laptop computer",
"specs": {
"cpu": "Intel i7",
"ram": "16GB",
"storage": {
"sort": "SSD",
"capability": "512GB"
}
},
"opinions": (
{"ranking": 5, "remark": "Glorious"},
{"ranking": 4, "remark": "Good worth"}
)
}
}
flattened = flatten_json(product_data)
for key, worth in flattened.gadgets():
print(f"{key}: {worth}")
Ausgabe:
product_id: 456
product_name: Laptop computer
product_specs_cpu: Intel i7
product_specs_ram: 16GB
product_specs_storage_type: SSD
product_specs_storage_capacity: 512GB
product_reviews_0_rating: 5
product_reviews_0_comment: Glorious
product_reviews_1_rating: 4
product_reviews_1_comment: Good worth
Die Funktion verwendet Rekursion, um beliebige Verschachtelungstiefen zu verarbeiten. Wenn es auf ein Wörterbuch stößt, verarbeitet es jedes Schlüssel-Wert-Paar und erstellt den abgeflachten Schlüssel, indem es die übergeordneten Schlüssel mit dem Trennzeichen verkettet.
Bei Hear wird der Index als Teil des Schlüssels verwendet. Dadurch können Sie die Reihenfolge und Struktur der Array-Elemente in der reduzierten Ausgabe beibehalten. Das Muster reviews_0_rating sagt Ihnen, dass dies die Bewertung aus der ersten Bewertung ist.
Der separator Mit dem Parameter können Sie das Ausgabeformat anpassen. Verwenden Sie je nach Bedarf Punkte für die Punktnotation, Unterstriche für „snake_case“ oder Schrägstriche für pfadähnliche Schlüssel.
Diese Funktion ist besonders nützlich, wenn Sie JSON-API-Antworten in Datenrahmen oder CSV-Zeilen konvertieren müssen, in denen jede Spalte einen eindeutigen Namen benötigt.
# 3. Deep Merge mehrerer JSON-Objekte
Für die Konfigurationsverwaltung müssen häufig mehrere JSON-Dateien zusammengeführt werden, die Standardeinstellungen, umgebungsspezifische Konfigurationen, Benutzereinstellungen und mehr enthalten. Ein einfaches dict.replace() Behandelt nur die oberste Ebene. Sie benötigen eine tiefe Zusammenführung, die verschachtelte Strukturen rekursiv kombiniert.
Hier ist eine Funktion, die JSON-Objekte tief zusammenführt:
def deep_merge_json(base, override):
"""
Deep merge two JSON objects, with override taking priority.
Args:
base: Base dictionary
override: Dictionary with values to override/add
Returns:
New dictionary with merged values
"""
end result = base.copy()
for key, worth in override.gadgets():
if key in end result and isinstance(end result(key), dict) and isinstance(worth, dict):
# Recursively merge nested dictionaries
end result(key) = deep_merge_json(end result(key), worth)
else:
# Override or add the worth
end result(key) = worth
return end result
Versuchen wir, Beispielkonfigurationsinformationen zusammenzuführen:
import json
# Default configuration
default_config = {
"database": {
"host": "localhost",
"port": 5432,
"timeout": 30,
"pool": {
"min": 2,
"max": 10
}
},
"cache": {
"enabled": True,
"ttl": 300
},
"logging": {
"stage": "INFO"
}
}
# Manufacturing overrides
prod_config = {
"database": {
"host": "prod-db.instance.com",
"pool": {
"min": 5,
"max": 50
}
},
"cache": {
"ttl": 600
},
"monitoring": {
"enabled": True
}
}
merged = deep_merge_json(default_config, prod_config)
print(json.dumps(merged, indent=2))
Ausgabe:
{
"database": {
"host": "prod-db.instance.com",
"port": 5432,
"timeout": 30,
"pool": {
"min": 5,
"max": 50
}
},
"cache": {
"enabled": true,
"ttl": 600
},
"logging": {
"stage": "INFO"
},
"monitoring": {
"enabled": true
}
}
Die Funktion führt verschachtelte Wörterbücher rekursiv zusammen. Wenn sowohl die Foundation als auch die Überschreibung Wörterbücher mit demselben Schlüssel enthalten, werden diese Wörterbücher zusammengeführt, anstatt sie vollständig zu ersetzen. Dadurch bleiben Werte erhalten, die nicht explizit überschrieben werden.
Beachten Sie, wie database.port Und database.timeout bleiben von der Standardkonfiguration, während database.host wird überschrieben. Die Pooleinstellungen werden additionally auf der verschachtelten Ebene zusammengeführt min Und max beide werden aktualisiert.
Die Funktion fügt auch neue Schlüssel hinzu, die in der Basiskonfiguration nicht vorhanden sind, wie z monitoring Abschnitt in der Produktionsüberschreibung.
Sie können mehrere Zusammenführungen zu Layer-Konfigurationen verketten:
final_config = deep_merge_json(
deep_merge_json(default_config, prod_config),
user_preferences
)
Dieses Muster kommt häufig in der Anwendungskonfiguration vor, wo Sie über Standardwerte, umgebungsspezifische Einstellungen und Laufzeitüberschreibungen verfügen.
# 4. JSON nach Schema oder Whitelist filtern
APIs geben oft mehr Daten zurück, als Sie benötigen. Große JSON-Antworten erschweren die Lesbarkeit Ihres Codes. Manchmal möchten Sie nur bestimmte Felder oder müssen vor der Protokollierung vertrauliche Daten entfernen.
Hier ist eine Funktion, die JSON filtert, um nur bestimmte Felder beizubehalten:
def filter_json(information, schema):
"""
Filter JSON to maintain solely fields laid out in schema.
Args:
information: Dictionary or JSON object to filter
schema: Dictionary defining which fields to maintain
Use True to maintain a discipline, nested dict for nested filtering
Returns:
Filtered dictionary containing solely specified fields
"""
if not isinstance(information, dict) or not isinstance(schema, dict):
return information
end result = {}
for key, worth in schema.gadgets():
if key not in information:
proceed
if worth is True:
# Maintain this discipline as-is
end result(key) = information(key)
elif isinstance(worth, dict):
# Recursively filter nested object
if isinstance(information(key), dict):
filtered_nested = filter_json(information(key), worth)
if filtered_nested:
end result(key) = filtered_nested
elif isinstance(information(key), checklist):
# Filter every merchandise within the checklist
filtered_list = ()
for merchandise in information(key):
if isinstance(merchandise, dict):
filtered_item = filter_json(merchandise, worth)
if filtered_item:
filtered_list.append(filtered_item)
else:
filtered_list.append(merchandise)
if filtered_list:
end result(key) = filtered_list
return end result
Lassen Sie uns eine Beispiel-API-Antwort filtern:
import json
# Pattern API response
api_response = {
"person": {
"id": 789,
"username": "Cayla",
"e-mail": "cayla@instance.com",
"password_hash": "secret123",
"profile": {
"title": "Cayla Smith",
"bio": "Software program developer",
"avatar_url": "https://instance.com/avatar.jpg",
"private_notes": "Inside notes"
},
"posts": (
{
"id": 1,
"title": "Hi there World",
"content material": "My first put up",
"views": 100,
"internal_score": 0.85
},
{
"id": 2,
"title": "Python Suggestions",
"content material": "Some ideas",
"views": 250,
"internal_score": 0.92
}
)
},
"metadata": {
"request_id": "abc123",
"server": "web-01"
}
}
# Schema defining what to maintain
public_schema = {
"person": {
"id": True,
"username": True,
"profile": {
"title": True,
"avatar_url": True
},
"posts": {
"id": True,
"title": True,
"views": True
}
}
}
filtered = filter_json(api_response, public_schema)
print(json.dumps(filtered, indent=2))
Ausgabe:
{
"person": {
"id": 789,
"username": "Cayla",
"profile": {
"title": "Cayla Smith",
"avatar_url": "https://instance.com/avatar.jpg"
},
"posts": (
{
"id": 1,
"title": "Hi there World",
"views": 100
},
{
"id": 2,
"title": "Python Suggestions",
"views": 250
}
)
}
}
Das Schema fungiert als Whitelist. Ein Feld festlegen auf True schließt es in die Ausgabe ein. Mithilfe eines verschachtelten Wörterbuchs können Sie verschachtelte Objekte filtern. Die Funktion wendet das Schema rekursiv auf verschachtelte Strukturen an.
Bei Arrays gilt das Schema für jedes Aspect. Im Beispiel wird das Posts-Array gefiltert, sodass jeder Publish nur Folgendes enthält: id, titleUnd viewswährend content material Und internal_score sind ausgeschlossen.
Beachten Sie, wie sensibel Felder sind password_hash Und private_notes erscheinen nicht in der Ausgabe. Dies macht die Funktion nützlich, um Daten vor der Protokollierung oder dem Senden an Frontend-Anwendungen zu bereinigen.
Sie können verschiedene Schemata für verschiedene Anwendungsfälle erstellen, z. B. ein Minimalschema für Listenansichten, ein detailliertes Schema für Einzelelementansichten und ein Admin-Schema, das alles umfasst.
# 5. Konvertieren von JSON in und aus der Punktnotation
Einige Systeme verwenden flache Schlüsselwertspeicher, Sie möchten jedoch mit verschachteltem JSON in Ihrem Code arbeiten. Dies lässt sich durch die Konvertierung zwischen flachen Punktnotationsschlüsseln und verschachtelten Strukturen erreichen.
Hier ist ein Funktionspaar für die bidirektionale Konvertierung.
// Konvertieren von JSON in Punktnotation
def json_to_dot_notation(information, parent_key=''):
"""
Convert nested JSON to flat dot-notation dictionary.
Args:
information: Nested dictionary
parent_key: Prefix for keys (utilized in recursion)
Returns:
Flat dictionary with dot-notation keys
"""
gadgets = {}
if isinstance(information, dict):
for key, worth in information.gadgets():
new_key = f"{parent_key}.{key}" if parent_key else key
if isinstance(worth, dict):
gadgets.replace(json_to_dot_notation(worth, new_key))
else:
gadgets(new_key) = worth
else:
gadgets(parent_key) = information
return gadgets
// Konvertieren der Punktnotation in JSON
def dot_notation_to_json(flat_data):
"""
Convert flat dot-notation dictionary to nested JSON.
Args:
flat_data: Dictionary with dot-notation keys
Returns:
Nested dictionary
"""
end result = {}
for key, worth in flat_data.gadgets():
elements = key.cut up('.')
present = end result
for i, half in enumerate(elements(:-1)):
if half not in present:
present(half) = {}
present = present(half)
present(elements(-1)) = worth
return end result
Testen wir die Spherical-Journey-Konvertierung:
import json
# Authentic nested JSON
config = {
"app": {
"title": "MyApp",
"model": "1.0.0"
},
"database": {
"host": "localhost",
"credentials": {
"username": "admin",
"password": "secret"
}
},
"options": {
"analytics": True,
"notifications": False
}
}
# Convert to dot notation (for atmosphere variables)
flat = json_to_dot_notation(config)
print("Flat format:")
for key, worth in flat.gadgets():
print(f" {key} = {worth}")
print("n" + "="*50 + "n")
# Convert again to nested JSON
nested = dot_notation_to_json(flat)
print("Nested format:")
print(json.dumps(nested, indent=2))
Ausgabe:
Flat format:
app.title = MyApp
app.model = 1.0.0
database.host = localhost
database.credentials.username = admin
database.credentials.password = secret
options.analytics = True
options.notifications = False
==================================================
Nested format:
{
"app": {
"title": "MyApp",
"model": "1.0.0"
},
"database": {
"host": "localhost",
"credentials": {
"username": "admin",
"password": "secret"
}
},
"options": {
"analytics": true,
"notifications": false
}
}
Der json_to_dot_notation Die Funktion flacht die Struktur ab, indem sie rekursiv durch verschachtelte Wörterbücher geht und Schlüssel mit Punkten verbindet. Im Gegensatz zur früheren Flatten-Funktion verarbeitet diese keine Arrays; Es ist für Konfigurationsdaten optimiert, bei denen es sich ausschließlich um Schlüsselwerte handelt.
Der dot_notation_to_json Funktion kehrt den Prozess um. Es teilt jeden Schlüssel in Punkte auf und baut die verschachtelte Struktur auf, indem es nach Bedarf Zwischenwörterbücher erstellt. Die Schleife verarbeitet alle Teile außer dem letzten und erstellt Verschachtelungsebenen. Dann weist es den Wert dem letzten Schlüssel zu.
Durch diesen Ansatz bleibt Ihre Konfiguration lesbar und wartbar, während gleichzeitig die Einschränkungen flacher Schlüsselwertsysteme eingehalten werden.
# Zusammenfassung
Die JSON-Verarbeitung geht über das Grundlegende hinaus json.hundreds(). In den meisten Projekten benötigen Sie Werkzeuge zum Navigieren in verschachtelten Strukturen, zum Transformieren von Formen, zum Zusammenführen von Konfigurationen, zum Filtern von Feldern und zum Konvertieren zwischen Formaten.
Die Techniken in diesem Artikel lassen sich auch auf andere Datenverarbeitungsaufgaben übertragen. Sie können diese Muster für XML, YAML oder benutzerdefinierte Datenformate ändern.
Beginnen Sie mit der sicheren Zugriffsfunktion, um KeyError-Ausnahmen in Ihrem Code zu verhindern. Fügen Sie die anderen hinzu, wenn Sie auf spezifische Anforderungen stoßen. Viel Spaß beim Codieren!
Bala Priya C ist ein Entwickler und technischer Redakteur aus Indien. Sie arbeitet gerne an der Schnittstelle von Mathematik, Programmierung, Datenwissenschaft und Inhaltserstellung. Zu ihren Interessen- und Fachgebieten gehören DevOps, Datenwissenschaft und Verarbeitung natürlicher Sprache. Sie liebt es zu lesen, zu schreiben, zu programmieren und Kaffee zu trinken! Derzeit arbeitet sie daran, zu lernen und ihr Wissen mit der Entwickler-Group zu teilen, indem sie Tutorials, Anleitungen, Meinungsbeiträge und mehr verfasst. Bala erstellt außerdem ansprechende Ressourcenübersichten und Programmier-Tutorials.
