Kuidas teisendada JSON Pythoni objektiks

Kuidas teisendada JSON Pythoni objektiks

Pythoni oma json raamatukogul on palju utiliite andmete kodeerimiseks ja dekodeerimiseks JSON-vormingus. Eelkõige, json.load() meetod dekodeerib failina loetud JSON-i ja json.loads() dekodeerida stringina loetud JSON-i. Üldiselt teisendatakse JSON-failide dekodeerimisel andmed Pythoni sõnaraamatuteks, kuid parameetri abil on võimalik need kohandatud objektiks teisendada. object_hook.

Oletame näiteks, et teil on järgmine JSON-objekt:

json_obj = """{
  "name" : "Felipe",
  "email" : "[email protected]",
  "age" : 29
}"""

ja järgmine klass:

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")

Kui helistame json.loads() koos User kui object_hook parameeter, User.__init__() meetodit kutsutakse koos JSON-i vastavaga dict sisendiks.

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]

Aga mis siis, kui teil on pesastatud JSON?

json.loads() tegelikult helistab object_hook funktsioon iga kord, kui see loeb stringist täielikult moodustatud JSON-objekti. Mõelge järgmisele JSON-ile, mis on tagastatud aadressilt Juhusliku kasutaja generaatori 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"
        }"""

Printige igal sammul dekodeeritud JSON, et näha, mis juhtub.

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() kutsub object_hook funktsiooni iga kord, kui see loeb täielikult moodustatud JSON-i, st iga kord, kui see sulgude paari sulgeb {}. Seejärel loob see kogu JSON-objekti, kasutades tulemuse object_hook funktsioon – pange tähele None (tagastusväärtus print) viimasel prinditud real.

Näitame selle probleemi jaoks kahte lahendust. Esimene on muuta meie User.__init__() sisendi suhtes paindlikum. Teeme seda kasutades __dict__ atribuut. Igal Pythoni objektil on a __dict__ atribuut, mis sisaldab iga atribuudi nime ja väärtust. Meie muudetud __init__() meetod värskendab seda sõnastikku:

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}")

Tutvuge meie praktilise ja praktilise Giti õppimise juhendiga, mis sisaldab parimaid tavasid, tööstusharus aktsepteeritud standardeid ja kaasas olevat petulehte. Lõpetage Giti käskude guugeldamine ja tegelikult õppima seda!

User Ian Walters, age 75, email [email protected]

Teine võimalik lahendus on kasutada collections.namedtuple klass:

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]

kus namedtuple('User', input.keys()) loob korteeži alamklassi nimega User sisendi võtmetega atribuutide nimedena ja User(**input) määrab atribuutidele vastavad väärtused.

Ajatempel:

Veel alates Stackabus