Jak przekonwertować JSON na obiekt Pythona
Pythona json
biblioteka posiada wiele narzędzi do kodowania i dekodowania danych w formacie JSON. W szczególności json.load()
Metoda dekoduje JSON odczytany jako plik, a metoda json.loads()
dekodować JSON odczytany jako ciąg znaków. Ogólnie rzecz biorąc, podczas dekodowania plików JSON dane są konwertowane do słowników Pythona, ale można je przekonwertować na obiekt niestandardowy za pomocą parametru object_hook
.
Załóżmy na przykład, że masz następujący obiekt JSON:
json_obj = """{
"name" : "Felipe",
"email" : "[email protected]",
"age" : 29
}"""
oraz następna klasa:
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")
Jeśli zadzwonimy json.loads()
w User
jak object_hook
parametr, User.__init__()
metoda zostanie wywołana z odpowiednim kodem JSON dict
jako wejście.
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]
Ale co, jeśli masz zagnieżdżony JSON?
json.loads()
faktycznie dzwoni object_hook
za każdym razem, gdy odczytuje w pełni uformowany obiekt JSON z łańcucha. Rozważ następujący kod JSON zwrócony z pliku Interfejs API losowego generatora użytkowników
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"
}"""
Wydrukujmy zdekodowany JSON na każdym kroku, aby zobaczyć, co się stanie:
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()
wzywa object_hook
za każdym razem, gdy odczytuje w pełni uformowany kod JSON, czyli za każdym razem, gdy zamyka parę nawiasów {}
. Następnie tworzy cały obiekt JSON, używając wyniku metody object_hook
funkcja – uwaga None
(wartość zwracana przez print
) w ostatnim wydrukowanym wierszu.
Pokażemy dwa obejścia tego problemu. Pierwszym z nich jest modyfikacja naszego User.__init__()
metoda, aby była bardziej elastyczna w odniesieniu do danych wejściowych. Zrobimy to za pomocą __dict__
atrybut. Każdy obiekt Pythona ma plik __dict__
atrybut, który przechowuje nazwę i wartość każdego atrybutu. Nasz zmodyfikowany __init__()
metoda zaktualizuje ten słownik:
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}")
Zapoznaj się z naszym praktycznym, praktycznym przewodnikiem dotyczącym nauki Git, zawierającym najlepsze praktyki, standardy przyjęte w branży i dołączoną ściągawkę. Zatrzymaj polecenia Google Git, a właściwie uczyć się to!
User Ian Walters, age 75, email [email protected]
Innym możliwym obejściem jest użycie collections.namedtuple
klasa:
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]
gdzie namedtuple('User', input.keys())
tworzy podklasę krotki o nazwie User
z kluczami wejściowymi jako nazwami atrybutów i User(**input)
przypisuje odpowiednie wartości atrybutom.