UPDATE
With Python3, you can do it in one line, using SimpleNamespace and object_hook:
import json
from types import SimpleNamespace
data = '{"name": "John Smith", "hometown": {"name": "New York", "id": 123}}'
# Parse JSON into an object with attributes corresponding to dict keys.
x = json.loads(data, object_hook=lambda d: SimpleNamespace(**d))
# Or, in Python 3.13+:
# json.loads(data, object_hook=SimpleNamespace)
print(x.name, x.hometown.name, x.hometown.id)
OLD ANSWER (Python2)
In Python2, you can do it in one line, using namedtuple and object_hook (but it's very slow with many nested objects):
import json
from collections import namedtuple
data = '{"name": "John Smith", "hometown": {"name": "New York", "id": 123}}'
# Parse JSON into an object with attributes corresponding to dict keys.
x = json.loads(data, object_hook=lambda d: namedtuple('X', d.keys())(*d.values()))
print x.name, x.hometown.name, x.hometown.id
or, to reuse this easily:
def _json_object_hook(d): return namedtuple('X', d.keys())(*d.values())
def json2obj(data): return json.loads(data, object_hook=_json_object_hook)
x = json2obj(data)
If you want it to handle keys that aren't good attribute names, check out namedtuple's rename parameter.
UPDATE
With Python3, you can do it in one line, using SimpleNamespace and object_hook:
import json
from types import SimpleNamespace
data = '{"name": "John Smith", "hometown": {"name": "New York", "id": 123}}'
# Parse JSON into an object with attributes corresponding to dict keys.
x = json.loads(data, object_hook=lambda d: SimpleNamespace(**d))
# Or, in Python 3.13+:
# json.loads(data, object_hook=SimpleNamespace)
print(x.name, x.hometown.name, x.hometown.id)
OLD ANSWER (Python2)
In Python2, you can do it in one line, using namedtuple and object_hook (but it's very slow with many nested objects):
import json
from collections import namedtuple
data = '{"name": "John Smith", "hometown": {"name": "New York", "id": 123}}'
# Parse JSON into an object with attributes corresponding to dict keys.
x = json.loads(data, object_hook=lambda d: namedtuple('X', d.keys())(*d.values()))
print x.name, x.hometown.name, x.hometown.id
or, to reuse this easily:
def _json_object_hook(d): return namedtuple('X', d.keys())(*d.values())
def json2obj(data): return json.loads(data, object_hook=_json_object_hook)
x = json2obj(data)
If you want it to handle keys that aren't good attribute names, check out namedtuple's rename parameter.
You could try this:
class User():
def __init__(self, name, username):
self.name = name
self.username = username
import json
j = json.loads(your_json)
u = User(**j)
Just create a new object and pass the parameters as a map.
You can have a JSON with objects too:
import json
class Address():
def __init__(self, street, number):
self.street = street
self.number = number
def __str__(self):
return "{0} {1}".format(self.street, self.number)
class User():
def __init__(self, name, address):
self.name = name
self.address = Address(**address)
def __str__(self):
return "{0} ,{1}".format(self.name, self.address)
if __name__ == '__main__':
js = '''{"name":"Cristian", "address":{"street":"Sesame","number":122}}'''
j = json.loads(js)
print(j)
u = User(**j)
print(u)
How do I convert a json file to a python class? - Stack Overflow
python - Serializing class instance to JSON - Stack Overflow
How should/can I convert loaded JSON data into Python objects?
how to convert json to python class? - Stack Overflow
Videos
Since it sounds like your data might be expected to be dynamic and you want the freedom to add more fields in the JSON object without reflecting the same changes in the model, I'd also suggest to check out typing.TypedDict instead a dataclass.
Here's an example with TypedDict, which should work in Python 3.7+. Since TypedDict was introduced in 3.8, I've instead imported it from typing_extensions so it's compatible with 3.7 code.
from __future__ import annotations
import json
from io import StringIO
from typing_extensions import TypedDict
class Account(TypedDict):
email: str
password: str
name: str
salary: int
json_data = StringIO("""{
"acc1":{
"email":"[email protected]",
"password":"acc1",
"name":"ACC1",
"salary":1
},
"acc2":{
"email":"[email protected]",
"password":"acc2",
"name":"ACC2",
"salary":2,
"someRandomKey": "string"
}
}
""")
data = json.load(json_data)
name_to_account: dict[str, Account] = data
acct = name_to_account['acc2']
# Your IDE should be able to offer auto-complete suggestions within the
# brackets, when you start typing or press 'Ctrl + Space' for example.
print(acct['someRandomKey'])
If you are set on using dataclasses to model your data, I'd suggest checking out a JSON serialization library like the dataclass-wizard (disclaimer: I am the creator) which should handle extraneous fields in the JSON data as mentioned, as well as a nested dataclass model if you find your data becoming more complex.
It also has a handy tool that you can use to generate a dataclass schema from JSON data, which can be useful for instance if you want to update your model class whenever you add new fields in the JSON file as mentioned.
This way you lose some dataclass features.
- Such as determining whether it is
optionalor not - Such as auto-completion feature
However, you are more familiar with your project and decide accordingly
There must be many methods, but this is one of them:
@dataclass
class Account(object):
email: str
password: str
name: str
salary: int
@classmethod
def from_json(cls, json_key):
file = json.load(open("1.txt"))
keys = [f.name for f in fields(cls)]
# or: keys = cls.__dataclass_fields__.keys()
json_data = file[json_key]
normal_json_data = {key: json_data[key] for key in json_data if key in keys}
anormal_json_data = {key: json_data[key] for key in json_data if key not in keys}
tmp = cls(**normal_json_data)
for anormal_key in anormal_json_data:
setattr(tmp,anormal_key,anormal_json_data[anormal_key])
return tmp
test = Account.from_json("acc1")
print(test.age)
The basic problem is that the JSON encoder json.dumps() only knows how to serialize a limited set of object types by default, all built-in types. List here: https://docs.python.org/3.3/library/json.html#encoders-and-decoders
One good solution would be to make your class inherit from JSONEncoder and then implement the JSONEncoder.default() function, and make that function emit the correct JSON for your class.
A simple solution would be to call json.dumps() on the .__dict__ member of that instance. That is a standard Python dict and if your class is simple it will be JSON serializable.
class Foo(object):
def __init__(self):
self.x = 1
self.y = 2
foo = Foo()
s = json.dumps(foo) # raises TypeError with "is not JSON serializable"
s = json.dumps(foo.__dict__) # s set to: {"x":1, "y":2}
The above approach is discussed in this blog posting:
Serializing arbitrary Python objects to JSON using _dict_
And, of course, Python offers a built-in function that accesses .__dict__ for you, called vars().
So the above example can also be done as:
s = json.dumps(vars(foo)) # s set to: {"x":1, "y":2}
There's one way that works great for me that you can try out:
json.dumps() can take an optional parameter default where you can specify a custom serializer function for unknown types, which in my case looks like
def serialize(obj):
"""JSON serializer for objects not serializable by default json code"""
if isinstance(obj, date):
serial = obj.isoformat()
return serial
if isinstance(obj, time):
serial = obj.isoformat()
return serial
return obj.__dict__
First two ifs are for date and time serialization
and then there is a obj.__dict__ returned for any other object.
the final call looks like:
json.dumps(myObj, default=serialize)
It's especially good when you are serializing a collection and you don't want to call __dict__ explicitly for every object. Here it's done for you automatically.
So far worked so good for me, looking forward for your thoughts.
Use object_hook special parameter in load functions of json module:
import json
class JSONObject:
def __init__( self, dict ):
vars(self).update( dict )
#this is valid json string
data='{"channel":{"lastBuild":"2013-11-12", "component":["test1", "test2"]}}'
jsonobject = json.loads( data, object_hook= JSONObject)
print( jsonobject.channel.component[0] )
print( jsonobject.channel.lastBuild )
This method have some issue, like some names in python are reserved. You can filter them out inside __init__ method.
the json module will load a Json into a list of maps/list. e.g:
>>> import json
>>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]')
[u'foo', {u'bar': [u'baz', None, 1.0, 2]}]
see http://docs.python.org/2/library/json.html
If you want to deserialize into a Class instance, see this SO thread: Parse JSON and store data in Python Class
I have never done this in python before but I'm pretty sure I could turn the retrieved JSON into a dictionary, but what is the best practice to convert the retrieved JSON into a class with its properties being items from the JSON.
So for example
{
"name":"Harry",
"job":"Mechanic"
}would yield
class Person:
def __init__(self, name, job):
self.name = name
self.job = jobAlso is there an easier way to do this.. something like a factory constructor.. ?
Hi there! My name's Avery and I've been working with Python for quite some time now. I've been recently working on a game for my girlfriend in Pygame for our 6th anniversary. While working on it I discovered that making a save system is quite troublesome, since I have to save all of the relevant data that is stored using class instances during the gameplay (I decided to use JSON as a save file format).
So that's why I decided to create my own first library that does exactly that, it's a single decorator that you put on a class that you wish to be converted to JSON along with all of its properties (and the nested properties of these properties and so on...)
Here's a short example from the README:
from jsonifable import Jsonifable
# it is not required to use dataclasses
# using them will just make this example shorter
from dataclasses import dataclass
@Jsonifable
@dataclass
class Person:
name: str
surname: str
person = Person("Avery", "Oliwa")
jsonified = person.to_json()
print(jsonified) # {"name": "Avery", "surname": "Oliwa"}I'm pretty proud of it, and any criticism is more than welcome!
Pypi: https://pypi.org/project/jsonifable/
GitHub: https://github.com/maciejoliwa/jsonifable