skip to Main Content

Assume I have several classes:

class Assignee:
    gid: str
    name: str
    
class Task:
    gid: str
    name: str
    created_at: datetime
    assignee: Assignee

and I receive a JSON, that I want to translate into my Task class instance:

{
 "gid": "#1",
 "name": "my task",
 "created_at": "2022-11-02T10:25:49.806Z",
 "assignee": {
  "gid": "#a1",
  "name": "assignee name"
 }
}

I need to get the strong typed result, not a dict. Is it possible to convert from JSON string to a class instance automatically?
In C# we can do it with JsonConvert.DeserializeObject<Task>(json_string).
In Python I found a jsonpickle library, but as far as I see, it cannot do it automatically. Am I missing anything?

In real life I have many more classes and JSON properties.

3

Answers


  1. Not quite what you are asking, but the json module already produces suitable dicts. All you need to do is define how to instantiate your classes given a dict.

    Part of this requires you to assume what type each key’s value must be instantiated as.

    class Assignee:
        @classmethod
        def from_dict(cls, d):
            return cls(d['gid'], d['name'])
    
    class Task:
        @classmethod
        def from_dict(cls, d):
            return cls(d['gid'], d['name'], d['created_at'], Assignee.from_dict(d['assignee']))
    
    t = Task.from_dict(json.load('{"gid": "#1", ...}'))
    
    Login or Signup to reply.
  2. Assuming the json properties match the property names exactly in the classes, you can use kwargs in the constructors to put the object together.

    import json
    
    class Assignee:
        def __init__(self, gid, name):
            self.gid = gid
            self.name = name
    
    class Task:
        def __init__(self, gid, name, created_at, assignee):
            self.gid = gid
            self.name = name
            self.created_at = created_at
            self.assignee = Assignee(**assignee)
    
    json_string = '{ "gid": "123", "name": "Bob", "created_at": "1/1/1990", "assignee": { "gid": "234", "name": "Alice" } }'
    
    # Instantiate Task with kwargs loaded from json
    my_task = Task(**json.loads(json_string))
    
    print(my_task.assignee.name)
    # prints 'Alice'
    
    Login or Signup to reply.
  3. Use pydantic. It has type validation (and other cool features) and is very easy to use:

    from pydantic import BaseModel
    from datetime import datetime
    
    class Assignee(BaseModel):
        gid: str
        name: str
        
    
    class Task(BaseModel):
        gid: str
        name: str
        created_at: datetime
        assignee: Assignee
    
    
    data = {
        "gid": "#1",
        "name": "my task",
        "created_at": "2022-11-02T10:25:49.806Z",
        "assignee": {
            "gid": "#a1",
            "name": "assignee name"
        }
    }
    
    Task(**data)
    >>>Task(gid='#1', name='my task', created_at=datetime.datetime(2022, 11, 2, 10, 25, 49, 806000, tzinfo=datetime.timezone.utc), assignee=Assignee(gid='#a1', name='assignee name'))
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search