Comment accéder aux clés imbriquées dans un objet JSON Python

PythonBeginner
Pratiquer maintenant

Introduction

La polyvalence de Python s'étend au travail avec les données JSON, un format largement utilisé pour stocker et échanger des informations. Les structures JSON peuvent être simples ou complexes avec des éléments imbriqués, similaires aux dictionnaires et aux listes Python. Dans ce tutoriel, vous apprendrez comment accéder et extraire des données de structures JSON imbriquées en Python grâce à des exercices pratiques.

À la fin de ce lab, vous serez capable de naviguer avec confiance dans les objets JSON, d'accéder aux clés profondément imbriquées et de travailler avec des tableaux imbriqués dans les applications Python.

Comprendre JSON en Python

JSON (JavaScript Object Notation) est un format d'échange de données léger, à la fois lisible par l'homme et analysable par une machine. En Python, les objets JSON sont représentés comme des dictionnaires, et les tableaux JSON comme des listes.

Commençons par créer un script Python simple pour explorer les données JSON :

  1. Ouvrez le WebIDE et créez un nouveau fichier en cliquant sur "File > New File" dans le menu.

  2. Enregistrez le fichier sous le nom basic_json.py dans le répertoire /home/labex/project/json_practice.

  3. Ajoutez le code suivant à basic_json.py :

import json

## A simple JSON object (represented as a Python dictionary)
person = {
    "name": "John Doe",
    "age": 30,
    "email": "john.doe@example.com",
    "is_employed": True,
    "hobbies": ["reading", "hiking", "coding"]
}

## Convert Python dictionary to JSON string
json_string = json.dumps(person, indent=2)
print("JSON as string:")
print(json_string)
print("\n" + "-" * 50 + "\n")

## Convert JSON string back to Python dictionary
parsed_json = json.loads(json_string)
print("Python dictionary:")
print(parsed_json)
print("\n" + "-" * 50 + "\n")

## Accessing basic elements
print("Basic access examples:")
print(f"Name: {parsed_json['name']}")
print(f"Age: {parsed_json['age']}")
print(f"First hobby: {parsed_json['hobbies'][0]}")
  1. Exécutez le script en ouvrant un terminal dans WebIDE et en exécutant :
cd /home/labex/project/json_practice
python3 basic_json.py

Vous devriez voir la sortie suivante :

JSON as string:
{
  "name": "John Doe",
  "age": 30,
  "email": "john.doe@example.com",
  "is_employed": true,
  "hobbies": [
    "reading",
    "hiking",
    "coding"
  ]
}

--------------------------------------------------

Python dictionary:
{'name': 'John Doe', 'age': 30, 'email': 'john.doe@example.com', 'is_employed': True, 'hobbies': ['reading', 'hiking', 'coding']}

--------------------------------------------------

Basic access examples:
Name: John Doe
Age: 30
First hobby: reading

Compréhension du code

  • json.dumps() convertit un objet Python en une chaîne formatée JSON
  • json.loads() analyse une chaîne JSON et la convertit en un objet Python
  • Pour accéder aux éléments d'un objet JSON, utilisez la syntaxe du dictionnaire : object_name['key']
  • Pour accéder aux éléments d'un tableau JSON, utilisez l'indexation de liste : array_name[index]

Cet exemple démontre les opérations de base pour travailler avec JSON en Python. Dans l'étape suivante, nous explorerons comment accéder aux structures JSON imbriquées.

Accéder aux clés de dictionnaires imbriqués

Les objets JSON contiennent souvent des structures imbriquées. En Python, nous pouvons accéder aux données imbriquées en utilisant plusieurs crochets ou en enchaînant les clés de dictionnaire.

Créons un nouveau script pour explorer les objets JSON imbriqués :

  1. Dans le WebIDE, créez un nouveau fichier et enregistrez-le sous le nom nested_dict.py dans le répertoire /home/labex/project/json_practice.

  2. Ajoutez le code suivant à nested_dict.py :

import json

## JSON with nested object
user_data = {
    "name": "John Doe",
    "age": 30,
    "contact": {
        "email": "john.doe@example.com",
        "phone": "555-1234",
        "address": {
            "street": "123 Main St",
            "city": "Anytown",
            "state": "CA",
            "zip": "12345"
        }
    },
    "preferences": {
        "theme": "dark",
        "notifications": True
    }
}

## Let's prettify and print the JSON structure
print("Full JSON structure:")
print(json.dumps(user_data, indent=2))
print("\n" + "-" * 50 + "\n")

## Accessing nested elements
print("Accessing nested elements:")
print(f"Email: {user_data['contact']['email']}")
print(f"City: {user_data['contact']['address']['city']}")
print(f"Theme: {user_data['preferences']['theme']}")
print("\n" + "-" * 50 + "\n")

## Safe access with get() method
print("Safe access with get():")
## get() returns None if key doesn't exist, or a default value if specified
phone = user_data.get('contact', {}).get('phone', 'Not available')
country = user_data.get('contact', {}).get('address', {}).get('country', 'Not specified')

print(f"Phone: {phone}")
print(f"Country: {country}")  ## This key doesn't exist but won't cause an error
  1. Exécutez le script dans le terminal :
cd /home/labex/project/json_practice
python3 nested_dict.py

Vous devriez voir une sortie similaire à :

Full JSON structure:
{
  "name": "John Doe",
  "age": 30,
  "contact": {
    "email": "john.doe@example.com",
    "phone": "555-1234",
    "address": {
      "street": "123 Main St",
      "city": "Anytown",
      "state": "CA",
      "zip": "12345"
    }
  },
  "preferences": {
    "theme": "dark",
    "notifications": true
  }
}

--------------------------------------------------

Accessing nested elements:
Email: john.doe@example.com
City: Anytown
Theme: dark

--------------------------------------------------

Safe access with get():
Phone: 555-1234
Country: Not specified

Comprendre l'accès imbriqué

Lorsque vous travaillez avec des structures JSON imbriquées, vous pouvez accéder aux éléments imbriqués en enchaînant les clés avec des crochets :

## Syntax for nested access
value = json_data['key1']['key2']['key3']

Cependant, cette approche peut provoquer des erreurs si une clé de la chaîne n'existe pas. La méthode la plus sûre consiste à utiliser la fonction get(), qui vous permet de fournir une valeur par défaut si une clé est manquante :

## Safe access with get() method
value = json_data.get('key1', {}).get('key2', {}).get('key3', 'default_value')

Ce modèle d'accès sûr est particulièrement précieux lorsque vous travaillez avec des réponses d'API ou d'autres données JSON externes où la structure pourrait ne pas être cohérente.

Travailler avec des tableaux imbriqués en JSON

Les données JSON incluent souvent des tableaux (listes en Python) qui peuvent contenir d'autres objets ou tableaux. Explorons comment accéder aux éléments à l'intérieur des tableaux imbriqués.

  1. Dans le WebIDE, créez un nouveau fichier et enregistrez-le sous le nom nested_arrays.py dans le répertoire /home/labex/project/json_practice.

  2. Ajoutez le code suivant à nested_arrays.py :

import json

## JSON with nested arrays
company_data = {
    "name": "Tech Innovations Inc",
    "founded": 2010,
    "departments": [
        {
            "name": "Engineering",
            "employees": [
                {"name": "Alice Johnson", "role": "Software Engineer", "skills": ["Python", "JavaScript", "AWS"]},
                {"name": "Bob Smith", "role": "DevOps Engineer", "skills": ["Docker", "Kubernetes", "Linux"]}
            ]
        },
        {
            "name": "Marketing",
            "employees": [
                {"name": "Carol Williams", "role": "Marketing Manager", "skills": ["SEO", "Content Strategy"]},
                {"name": "Dave Brown", "role": "Social Media Specialist", "skills": ["Facebook Ads", "Instagram"]}
            ]
        }
    ],
    "locations": ["San Francisco", "New York", "London"]
}

## Print the JSON structure
print("Company Data:")
print(json.dumps(company_data, indent=2))
print("\n" + "-" * 50 + "\n")

## Accessing elements in arrays
print("Accessing array elements:")
print(f"First location: {company_data['locations'][0]}")
print(f"Number of departments: {len(company_data['departments'])}")
print(f"First department name: {company_data['departments'][0]['name']}")
print("\n" + "-" * 50 + "\n")

## Iterating through nested arrays
print("All employees and their skills:")
for department in company_data['departments']:
    dept_name = department['name']
    print(f"\nDepartment: {dept_name}")
    print("-" * 20)

    for employee in department['employees']:
        print(f"  {employee['name']} ({employee['role']})")
        print(f"  Skills: {', '.join(employee['skills'])}")
        print()

## Finding specific data in nested arrays
print("-" * 50 + "\n")
print("Finding employees with Python skills:")

for department in company_data['departments']:
    for employee in department['employees']:
        if "Python" in employee['skills']:
            print(f"  {employee['name']} in {department['name']} department")
  1. Exécutez le script dans le terminal :
cd /home/labex/project/json_practice
python3 nested_arrays.py

Vous devriez voir une sortie similaire à :

Company Data:
{
  "name": "Tech Innovations Inc",
  "founded": 2010,
  "departments": [
    {
      "name": "Engineering",
      "employees": [
        {
          "name": "Alice Johnson",
          "role": "Software Engineer",
          "skills": [
            "Python",
            "JavaScript",
            "AWS"
          ]
        },
        {
          "name": "Bob Smith",
          "role": "DevOps Engineer",
          "skills": [
            "Docker",
            "Kubernetes",
            "Linux"
          ]
        }
      ]
    },
    {
      "name": "Marketing",
      "employees": [
        {
          "name": "Carol Williams",
          "role": "Marketing Manager",
          "skills": [
            "SEO",
            "Content Strategy"
          ]
        },
        {
          "name": "Dave Brown",
          "role": "Social Media Specialist",
          "skills": [
            "Facebook Ads",
            "Instagram"
          ]
        }
      ]
    }
  ],
  "locations": [
    "San Francisco",
    "New York",
    "London"
  ]
}

--------------------------------------------------

Accessing array elements:
First location: San Francisco
Number of departments: 2
First department name: Engineering

--------------------------------------------------

All employees and their skills:

Department: Engineering
--------------------
  Alice Johnson (Software Engineer)
  Skills: Python, JavaScript, AWS

  Bob Smith (DevOps Engineer)
  Skills: Docker, Kubernetes, Linux


Department: Marketing
--------------------
  Carol Williams (Marketing Manager)
  Skills: SEO, Content Strategy

  Dave Brown (Social Media Specialist)
  Skills: Facebook Ads, Instagram

--------------------------------------------------

Finding employees with Python skills:
  Alice Johnson in Engineering department

Comprendre l'accès aux tableaux imbriqués

Travailler avec des tableaux imbriqués en JSON implique une combinaison de :

  1. Accès indexé : Utilisez des crochets avec un index pour accéder à des éléments de tableau spécifiques (array[0])
  2. Accès aux propriétés imbriquées : Enchaînez les clés de dictionnaire et les indices de tableau (data['departments'][0]['employees'])
  3. Itération : Utilisez des boucles pour traiter plusieurs éléments dans les tableaux

Le modèle le plus courant pour travailler avec des tableaux imbriqués est d'utiliser des boucles for imbriquées :

for outer_item in json_data['outer_array']:
    for inner_item in outer_item['inner_array']:
        ## Process the inner_item
        print(inner_item['property'])

Cette approche vous permet de parcourir des structures imbriquées complexes et d'extraire les données spécifiques dont vous avez besoin.

Gérer les clés manquantes et la prévention des erreurs

Lorsque vous travaillez avec des structures JSON complexes, en particulier à partir de sources externes comme les API, il est important de gérer les erreurs potentielles qui surviennent lorsque des clés sont manquantes. Explorons les techniques pour accéder en toute sécurité aux données JSON imbriquées.

  1. Dans le WebIDE, créez un nouveau fichier et enregistrez-le sous le nom error_handling.py dans le répertoire /home/labex/project/json_practice.

  2. Ajoutez le code suivant à error_handling.py :

import json

## JSON with inconsistent structure
api_response = {
    "status": "success",
    "data": {
        "users": [
            {
                "id": 1,
                "name": "John Doe",
                "contact": {
                    "email": "john.doe@example.com",
                    "phone": "555-1234"
                },
                "roles": ["admin", "user"]
            },
            {
                "id": 2,
                "name": "Jane Smith",
                ## Missing contact info
                "roles": ["user"]
            },
            {
                "id": 3,
                "name": "Bob Johnson",
                "contact": {
                    ## Only has email, no phone
                    "email": "bob.johnson@example.com"
                }
                ## Missing roles
            }
        ]
    }
}

print("API Response Structure:")
print(json.dumps(api_response, indent=2))
print("\n" + "-" * 50 + "\n")

## Approach 1: Using try-except blocks
print("Method 1: Using try-except blocks")
print("-" * 30)

for user in api_response["data"]["users"]:
    print(f"User: {user['name']}")

    ## Get email
    try:
        email = user['contact']['email']
        print(f"  Email: {email}")
    except (KeyError, TypeError):
        print("  Email: Not available")

    ## Get phone
    try:
        phone = user['contact']['phone']
        print(f"  Phone: {phone}")
    except (KeyError, TypeError):
        print("  Phone: Not available")

    ## Get roles
    try:
        roles = ", ".join(user['roles'])
        print(f"  Roles: {roles}")
    except (KeyError, TypeError):
        print("  Roles: None assigned")

    print()

## Approach 2: Using get() method with defaults
print("\n" + "-" * 50 + "\n")
print("Method 2: Using get() method with defaults")
print("-" * 30)

for user in api_response["data"]["users"]:
    print(f"User: {user['name']}")

    ## Get contact info with nested get() calls
    contact = user.get('contact', {})
    email = contact.get('email', 'Not available')
    phone = contact.get('phone', 'Not available')

    print(f"  Email: {email}")
    print(f"  Phone: {phone}")

    ## Get roles with default empty list
    roles = user.get('roles', [])
    roles_str = ", ".join(roles) if roles else "None assigned"
    print(f"  Roles: {roles_str}")

    print()
  1. Exécutez le script dans le terminal :
cd /home/labex/project/json_practice
python3 error_handling.py

Vous devriez voir une sortie similaire à :

API Response Structure:
{
  "status": "success",
  "data": {
    "users": [
      {
        "id": 1,
        "name": "John Doe",
        "contact": {
          "email": "john.doe@example.com",
          "phone": "555-1234"
        },
        "roles": [
          "admin",
          "user"
        ]
      },
      {
        "id": 2,
        "name": "Jane Smith",
        "roles": [
          "user"
        ]
      },
      {
        "id": 3,
        "name": "Bob Johnson",
        "contact": {
          "email": "bob.johnson@example.com"
        }
      }
    ]
  }
}

--------------------------------------------------

Method 1: Using try-except blocks
------------------------------
User: John Doe
  Email: john.doe@example.com
  Phone: 555-1234
  Roles: admin, user

User: Jane Smith
  Email: Not available
  Phone: Not available
  Roles: user

User: Bob Johnson
  Email: bob.johnson@example.com
  Phone: Not available
  Roles: None assigned


--------------------------------------------------

Method 2: Using get() method with defaults
------------------------------
User: John Doe
  Email: john.doe@example.com
  Phone: 555-1234
  Roles: admin, user

User: Jane Smith
  Email: Not available
  Phone: Not available
  Roles: user

User: Bob Johnson
  Email: bob.johnson@example.com
  Phone: Not available
  Roles: None assigned

Comprendre les techniques de gestion des erreurs

L'exemple démontre deux approches principales pour accéder en toute sécurité aux données JSON imbriquées :

  1. Blocs Try-Except

    • Enveloppez l'accès potentiellement risqué dans des blocs try-except
    • Interceptez KeyError (clé de dictionnaire manquante) et TypeError (tentative d'accès à une clé sur un non-dictionnaire)
    • Fournissez des valeurs de repli lorsque des erreurs se produisent
  2. Méthode get() enchaînée

    • Utilisez la méthode get() du dictionnaire qui prend une valeur par défaut comme deuxième argument
    • Enchaînez plusieurs appels get() pour les structures imbriquées
    • Fournit un code plus propre sans gestion des exceptions

L'approche de la méthode get() est généralement préférée pour sa lisibilité et sa concision lors du traitement des structures JSON imbriquées. Elle vous permet de fournir des valeurs par défaut à chaque niveau d'imbrication.

## Safe nested access pattern
value = data.get('level1', {}).get('level2', {}).get('level3', 'default_value')

L'utilisation de ces techniques de gestion des erreurs rendra votre code plus robuste lorsque vous travaillerez avec des données JSON provenant de diverses sources.

Exercice pratique : Création d'un extracteur de données JSON

Mettons vos connaissances en pratique en créant un programme qui extrait des informations spécifiques d'une structure JSON complexe. Cela pourrait représenter un scénario réel où vous recevez des données JSON d'une API et devez les traiter.

  1. Dans le WebIDE, créez un nouveau fichier et enregistrez-le sous le nom json_extractor.py dans le répertoire /home/labex/project/json_practice.

  2. Ajoutez le code suivant à json_extractor.py :

import json

## A complex nested JSON structure (e.g., from a weather API)
weather_data = {
    "location": {
        "name": "New York",
        "region": "New York",
        "country": "United States of America",
        "lat": 40.71,
        "lon": -74.01,
        "timezone": "America/New_York"
    },
    "current": {
        "temp_c": 22.0,
        "temp_f": 71.6,
        "condition": {
            "text": "Partly cloudy",
            "icon": "//cdn.weatherapi.com/weather/64x64/day/116.png",
            "code": 1003
        },
        "wind_mph": 6.9,
        "wind_kph": 11.2,
        "wind_dir": "ENE",
        "humidity": 65,
        "cloud": 75,
        "feelslike_c": 22.0,
        "feelslike_f": 71.6
    },
    "forecast": {
        "forecastday": [
            {
                "date": "2023-09-20",
                "day": {
                    "maxtemp_c": 24.3,
                    "maxtemp_f": 75.7,
                    "mintemp_c": 18.6,
                    "mintemp_f": 65.5,
                    "condition": {
                        "text": "Patchy rain possible",
                        "icon": "//cdn.weatherapi.com/weather/64x64/day/176.png",
                        "code": 1063
                    },
                    "daily_chance_of_rain": 85
                },
                "astro": {
                    "sunrise": "06:41 AM",
                    "sunset": "07:01 PM",
                    "moonrise": "10:15 AM",
                    "moonset": "08:52 PM"
                },
                "hour": [
                    {
                        "time": "2023-09-20 00:00",
                        "temp_c": 20.1,
                        "condition": {
                            "text": "Clear",
                            "icon": "//cdn.weatherapi.com/weather/64x64/night/113.png",
                            "code": 1000
                        },
                        "chance_of_rain": 0
                    },
                    {
                        "time": "2023-09-20 12:00",
                        "temp_c": 23.9,
                        "condition": {
                            "text": "Overcast",
                            "icon": "//cdn.weatherapi.com/weather/64x64/day/122.png",
                            "code": 1009
                        },
                        "chance_of_rain": 20
                    }
                ]
            },
            {
                "date": "2023-09-21",
                "day": {
                    "maxtemp_c": 21.2,
                    "maxtemp_f": 70.2,
                    "mintemp_c": 16.7,
                    "mintemp_f": 62.1,
                    "condition": {
                        "text": "Heavy rain",
                        "icon": "//cdn.weatherapi.com/weather/64x64/day/308.png",
                        "code": 1195
                    },
                    "daily_chance_of_rain": 92
                },
                "astro": {
                    "sunrise": "06:42 AM",
                    "sunset": "06:59 PM",
                    "moonrise": "11:30 AM",
                    "moonset": "09:15 PM"
                }
            }
        ]
    }
}

def extract_weather_summary(data):
    """
    Extract and format a weather summary from the provided data.
    """
    try:
        ## Location information
        location = data.get("location", {})
        location_name = location.get("name", "Unknown")
        country = location.get("country", "Unknown")

        ## Current weather
        current = data.get("current", {})
        temp_c = current.get("temp_c", "N/A")
        temp_f = current.get("temp_f", "N/A")
        condition = current.get("condition", {}).get("text", "Unknown")
        humidity = current.get("humidity", "N/A")

        ## Forecast
        forecast_days = data.get("forecast", {}).get("forecastday", [])

        ## Build summary string
        summary = f"Weather Summary for {location_name}, {country}\n"
        summary += f"==================================================\n\n"
        summary += f"Current Conditions:\n"
        summary += f"  Temperature: {temp_c}°C ({temp_f}°F)\n"
        summary += f"  Condition: {condition}\n"
        summary += f"  Humidity: {humidity}%\n\n"

        if forecast_days:
            summary += "Forecast:\n"
            for day_data in forecast_days:
                date = day_data.get("date", "Unknown date")
                day = day_data.get("day", {})
                max_temp = day.get("maxtemp_c", "N/A")
                min_temp = day.get("mintemp_c", "N/A")
                condition = day.get("condition", {}).get("text", "Unknown")
                rain_chance = day.get("daily_chance_of_rain", "N/A")

                summary += f"  {date}:\n"
                summary += f"    High: {max_temp}°C, Low: {min_temp}°C\n"
                summary += f"    Condition: {condition}\n"
                summary += f"    Chance of Rain: {rain_chance}%\n"

                ## Get sunrise and sunset times if available
                astro = day_data.get("astro", {})
                if astro:
                    sunrise = astro.get("sunrise", "N/A")
                    sunset = astro.get("sunset", "N/A")
                    summary += f"    Sunrise: {sunrise}, Sunset: {sunset}\n"

                summary += "\n"

        return summary

    except Exception as e:
        return f"Error extracting weather data: {str(e)}"

## Print the full JSON data
print("Original Weather Data:")
print(json.dumps(weather_data, indent=2))
print("\n" + "-" * 60 + "\n")

## Extract and print the weather summary
weather_summary = extract_weather_summary(weather_data)
print(weather_summary)

## Save the summary to a file
with open("weather_summary.txt", "w") as file:
    file.write(weather_summary)

print("\nWeather summary has been saved to 'weather_summary.txt'")
  1. Exécutez le script dans le terminal :
cd /home/labex/project/json_practice
python3 json_extractor.py
  1. Après avoir exécuté le script, vous pouvez afficher le fichier de résumé généré :
cat weather_summary.txt

Vous verrez le résumé météorologique formaté extrait de la structure JSON complexe.

Comprendre l'extracteur JSON

Cet exercice pratique démontre plusieurs concepts importants pour travailler avec des données JSON imbriquées :

  1. Extraction sécurisée des données

    • Utilisation de la méthode get() avec des valeurs par défaut pour gérer les clés manquantes
    • Accès aux données imbriquées avec des appels get() enchaînés
    • Gestion des erreurs avec des blocs try-except
  2. Transformation des données

    • Conversion des données JSON en un format lisible par l'homme
    • Itération à travers des tableaux imbriqués pour traiter plusieurs éléments
    • Extraction uniquement des informations pertinentes d'une structure complexe
  3. Programmation défensive

    • Anticiper et gérer les problèmes potentiels
    • Fournir des valeurs par défaut lorsque des données sont manquantes
    • Intercepter les exceptions pour éviter les plantages du programme

Ce modèle d'extraction, de transformation et de présentation des données JSON est courant dans de nombreuses applications réelles, telles que :

  • Traitement des réponses d'API
  • Génération de rapports à partir de données
  • Filtrage et affichage d'informations pour les utilisateurs

En suivant ces modèles, vous pouvez travailler de manière fiable avec des données JSON de toute complexité.

Résumé

Dans ce laboratoire, vous avez appris à travailler avec des structures JSON imbriquées en Python :

  1. Gestion de base du JSON - Conversion entre les objets Python et les chaînes JSON en utilisant json.dumps() et json.loads().

  2. Accès aux clés de dictionnaire imbriquées - Utilisation de la notation en chaîne avec des crochets pour accéder aux valeurs profondément imbriquées dans les objets JSON.

  3. Utilisation des tableaux imbriqués - Navigation et extraction de données à partir de tableaux au sein de structures JSON en utilisant l'indexation et l'itération.

  4. Techniques de gestion des erreurs - Mise en œuvre de schémas d'accès sécurisés avec des blocs try-except et la méthode get() pour gérer les clés manquantes.

  5. Extraction pratique des données - Construction d'une application complète qui extrait, transforme et présente des données à partir d'une structure JSON complexe.

Ces compétences sont essentielles pour travailler avec des données provenant d'API, de fichiers de configuration et d'autres scénarios d'échange de données. Vous avez maintenant les bases pour gérer en toute confiance les données JSON de toute complexité dans vos applications Python.

Pour un apprentissage plus approfondi, envisagez d'explorer :

  • Travailler avec des API réelles qui renvoient des données JSON
  • Utiliser des bibliothèques comme pandas pour analyser les données JSON
  • Mettre en œuvre la validation JSON avec jsonschema
  • Créer et manipuler des structures JSON personnalisées