Comment convertir JSON en objet Python
Python json
La bibliothèque dispose de nombreux utilitaires pour encoder et décoder les données au format JSON. En particulier, le json.load()
décode un JSON lu comme un fichier, et la json.loads()
décoder un JSON lu comme une chaîne. En général, lors du décodage des fichiers JSON, les données sont converties en dictionnaires Python, mais il est possible de les convertir en un objet personnalisé en utilisant le paramètre object_hook
.
Par exemple, supposons que vous ayez l'objet JSON suivant :
json_obj = """{
"name" : "Felipe",
"email" : "[email protected]",
"age" : 29
}"""
et la classe suivante :
class User():
name : str
email : str
age : int
def __init__(self, input):
self.name = input.get("name")
self.email = input.get("email")
self.age = input.get("age")
Si nous appelons json.loads()
comprenant User
car object_hook
paramètre, le User.__init__()
la méthode sera appelée avec le JSON correspondant dict
comme entrée.
import json
user = json.loads(json_obj, object_hook = User)
print(f"User {user.name}, age {user.age}, email {user.email}")
User Felipe, age 29, email [email protected]
Mais que se passe-t-il si vous avez un JSON imbriqué ?
json.loads()
appelle en fait le object_hook
fonction chaque fois qu'il lit un objet JSON entièrement formé à partir de la chaîne. Considérez le JSON suivant, renvoyé par le API de générateur d'utilisateurs aléatoires
json_obj = """{
"gender": "male",
"name": {
"title": "Mr",
"first": "Ian",
"last": "Walters"
},
"location": {
"street": {
"number": 3161,
"name": "Saddle Dr"
},
"city": "Bendigo",
"state": "Western Australia",
"country": "Australia",
"postcode": 4285,
"coordinates": {
"latitude": "-84.7903",
"longitude": "-29.1020"
},
"timezone": {
"offset": "+9:00",
"description": "Tokyo, Seoul, Osaka, Sapporo, Yakutsk"
}
},
"email": "[email protected]",
"login": {
"uuid": "6ee5b2e8-01c3-4314-8f7f-80059f5dd9ec",
"username": "lazyzebra585",
"password": "walter",
"salt": "afXmogsa",
"md5": "a40e87023b57a4a60c7cb398584cbac3",
"sha1": "74caf43400be38cce60a8da2e6d1c367246505c2",
"sha256": "1becdf34bcc6704726c7e9b38821a5792f9dd0689d30789fb5e099a6e51e860a"
},
"dob": {
"date": "1947-06-06T02:45:41.895Z",
"age": 75
},
"registered": {
"date": "2003-03-25T00:15:32.791Z",
"age": 19
},
"phone": "06-9388-6976",
"cell": "0469-101-424",
"id": {
"name": "TFN",
"value": "561493929"
},
"picture": {
"large": "https://randomuser.me/api/portraits/men/32.jpg",
"medium": "https://randomuser.me/api/portraits/med/men/32.jpg",
"thumbnail": "https://randomuser.me/api/portraits/thumb/men/32.jpg"
},
"nat": "AU"
}"""
Imprimons le JSON décodé à chaque étape pour voir ce qui se passe :
json.loads(json_obj, object_hook = print)
{'title': 'Mr', 'first': 'Ian', 'last': 'Walters'}
{'number': 3161, 'name': 'Saddle Dr'}
{'latitude': '-84.7903', 'longitude': '-29.1020'}
{'offset': '+9:00', 'description': 'Tokyo, Seoul, Osaka, Sapporo, Yakutsk'}
{'street': None, 'city': 'Bendigo', 'state': 'Western Australia', 'country': 'Australia', 'postcode': 4285, 'coordinates': None, 'timezone': None}
{'uuid': '6ee5b2e8-01c3-4314-8f7f-80059f5dd9ec', 'username': 'lazyzebra585', 'password': 'walter', 'salt': 'afXmogsa', 'md5': 'a40e87023b57a4a60c7cb398584cbac3', 'sha1': '74caf43400be38cce60a8da2e6d1c367246505c2', 'sha256': '1becdf34bcc6704726c7e9b38821a5792f9dd0689d30789fb5e099a6e51e860a'}
{'date': '1947-06-06T02:45:41.895Z', 'age': 75}
{'date': '2003-03-25T00:15:32.791Z', 'age': 19}
{'name': 'TFN', 'value': '561493929'}
{'large': 'https://randomuser.me/api/portraits/men/32.jpg', 'medium': 'https://randomuser.me/api/portraits/med/men/32.jpg', 'thumbnail': 'https://randomuser.me/api/portraits/thumb/men/32.jpg'}
{'gender': 'male', 'name': None, 'location': None, 'email': '[email protected]', 'login': None, 'dob': None, 'registered': None, 'phone': '06-9388-6976', 'cell': '0469-101-424', 'id': None, 'picture': None, 'nat': 'AU'}
So json.loads()
appelle le object_hook
fonction à chaque fois qu'il lit un JSON entièrement formé, c'est-à-dire à chaque fois qu'il ferme une paire de parenthèses {}
. Ensuite, il crée l'objet JSON entier en utilisant le résultat de la object_hook
fonction - notez la None
(la valeur de retour de print
) dans la dernière ligne imprimée.
Nous allons montrer deux solutions de contournement pour ce problème. La première consiste à modifier notre User.__init__()
méthode pour être plus flexible par rapport à l'entrée. Nous allons le faire en utilisant le __dict__
attribut. Chaque objet Python a un __dict__
attribut contenant le nom et la valeur de chaque attribut. Notre modifié __init__()
met à jour ce dictionnaire :
class User():
def __init__(self, input):
self.__dict__.update(input)
user = json.loads(json_obj, object_hook = User)
print(f"User {user.name.first} {user.name.last}, age {user.dob.age}, email {user.email}")
Consultez notre guide pratique et pratique pour apprendre Git, avec les meilleures pratiques, les normes acceptées par l'industrie et la feuille de triche incluse. Arrêtez de googler les commandes Git et en fait apprendre il!
User Ian Walters, age 75, email [email protected]
Une autre solution possible consiste à utiliser le collections.namedtuple
classe:
from collections import namedtuple
def create_user(input):
User = namedtuple('User', input.keys())
return User(**input)
user = json.loads(json_obj, object_hook=create_user)
print(f"User {user.name.first} {user.name.last}, age {user.dob.age}, email {user.email}")
User Ian Walters, age 75, email [email protected]
De namedtuple('User', input.keys())
crée une sous-classe de tuple appelée User
avec les clés de l'entrée comme noms d'attributs, et User(**input)
attribue les valeurs correspondantes aux attributs.