Hoe JSON naar Python-object te converteren
Python's json
bibliotheek heeft veel hulpprogramma's voor het coderen en decoderen van gegevens in JSON-indeling. Met name de json.load()
methode decodeert een JSON gelezen als een bestand, en de json.loads()
decodeer een JSON gelezen als een string. Over het algemeen worden bij het decoderen van JSON-bestanden de gegevens geconverteerd naar Python-woordenboeken, maar het is mogelijk om deze naar een aangepast object te converteren met behulp van de parameter object_hook
.
Stel dat u het volgende JSON-object hebt:
json_obj = """{
"name" : "Felipe",
"email" : "[email protected]",
"age" : 29
}"""
en de volgende klasse:
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")
Als we bellen json.loads()
Met User
de object_hook
parameter, de User.__init__()
methode wordt aangeroepen met de corresponderende JSON dict
als invoer.
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]
Maar wat als je een geneste JSON hebt?
json.loads()
noemt eigenlijk de object_hook
functie elke keer dat het een volledig gevormd JSON-object uit de string leest. Beschouw de volgende JSON, teruggestuurd van de Willekeurige User Generator-API
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"
}"""
Laten we de gedecodeerde JSON bij elke stap afdrukken om te zien wat er gebeurt:
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()
roept de object_hook
functie elke keer dat het een volledig gevormde JSON leest, dat wil zeggen elke keer dat het een haakjespaar sluit {}
. Vervolgens wordt het hele JSON-object gemaakt met behulp van het resultaat van de object_hook
functie - let op de None
(de retourwaarde van print
) in de laatst afgedrukte regel.
We zullen twee oplossingen voor dit probleem laten zien. De eerste is om onze te wijzigen User.__init__()
methode om flexibeler te zijn met betrekking tot de invoer. Dit doen we aan de hand van de __dict__
attribuut. Elk Python-object heeft een __dict__
attribuut dat de naam en waarde van elk attribuut bevat. Onze gewijzigd __init__()
methode zal dit woordenboek bijwerken:
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}")
Bekijk onze praktische, praktische gids voor het leren van Git, met best-practices, door de industrie geaccepteerde normen en bijgevoegd spiekbriefje. Stop met Googlen op Git-commando's en eigenlijk leren het!
User Ian Walters, age 75, email [email protected]
Een andere mogelijke oplossing is het gebruik van de collections.namedtuple
klasse:
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]
WAAR namedtuple('User', input.keys())
creรซert een tuple-subklasse met de naam User
met de invoersleutels als kenmerknamen, en User(**input)
wijst de corresponderende waarden toe aan de attributen.