353

I am new to Python and I am playing with JSON data. I would like to dynamically build a JSON object by adding some key-value to an existing JSON object.

I tried the following but I get TypeError: 'str' object does not support item assignment:

import json

json_data = json.dumps({})
json_data["key"] = "value"

print 'JSON: ', json_data
martineau
  • 119,623
  • 25
  • 170
  • 301
Backo
  • 18,291
  • 27
  • 103
  • 170

8 Answers8

713

You build the object before encoding it to a JSON string:

import json

data = {}
data['key'] = 'value'
json_data = json.dumps(data)

JSON is a serialization format, textual data representing a structure. It is not, itself, that structure.

Dan Loughney
  • 4,647
  • 3
  • 25
  • 40
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • 3
    Your solution worked like a charm for me. I couldn't understand the meaning of your last line though, could you please elaborate that a bit. Thanks. – akki Jun 25 '15 at 12:10
  • 6
    @akki: the OP tried to treat the JSON string (a series of characters that encode an object) as the object itself. They tried to use `json_data['key'] = 'value'`, which won't work because `json_data` is not a Python dictionary. – Martijn Pieters Jun 25 '15 at 12:12
  • given an object can one transform the object into JSON or a dictionary somehow automatically? – Charlie Parker Mar 26 '19 at 18:15
  • @CharlieParker: that's way too broad. Python objects are not that simply reflected into JSON, as JSON is quite a limited format with only a few data types. There are a lot of questions here on SO already that cover *specific* object types and JSON, such as Django or SQLAlchemy models, etc. – Martijn Pieters Mar 26 '19 at 18:16
  • I'm trying to convert all of the `module==version` lines from `pip freeze` into key/value pairs in a JSON string. Using a dictionary to store the intermediate values does work, but I was hoping for a built-in solution that can do this in one pass. I'd rather not write a 40-line monstrosity just to save a handful of clock cycles. – Alex Jansen Jun 06 '19 at 02:25
  • 1
    @AlexJohnson: `pip list` gives you the same information and can output JSON: `pip list --format=json` – Martijn Pieters Jun 07 '19 at 23:33
42

You can create the Python dictionary and serialize it to JSON in one line and it's not even ugly.

my_json_string = json.dumps({'key1': val1, 'key2': val2})
sscarduzio
  • 5,938
  • 5
  • 42
  • 54
25

There is already a solution provided which allows building a dictionary, (or nested dictionary for more complex data), but if you wish to build an object, then perhaps try 'ObjDict'. This gives much more control over the json to be created, for example retaining order, and allows building as an object which may be a preferred representation of your concept.

pip install objdict first.

from objdict import ObjDict

data = ObjDict()
data.key = 'value'
json_data = data.dumps()
innov8
  • 2,093
  • 2
  • 24
  • 31
  • 2
    this is exactly what I was looking for! Given that dicts are unordered, though you could sort by alphabetical order when calling `json.dumps` i.e. `json.dumps(response, sort_keys=True, indent=4)`, but then you're stuck with alphabetical order and not your preferred ordering, grouping and representation – Jonathan Sep 05 '17 at 19:16
  • The JSON specification does not allow for ordered properties on JSON objects and any endpoint expecting specific ordering of properties on an object will be disappointed. If specific ordering is required, you will need to place your values in an array within the object. – Rodney P. Barbati Feb 06 '23 at 19:00
20
  • json.loads take a string as input and returns a dictionary as output.
  • json.dumps take a dictionary as input and returns a string as output.

If you need to convert JSON data into a python object, it can do so with Python3, in one line without additional installations, using SimpleNamespace and object_hook:

from string

import json
from types import SimpleNamespace

string = '{"foo":3, "bar":{"x":1, "y":2}}'

# Parse JSON into an object with attributes corresponding to dict keys.
x = json.loads(string, object_hook=lambda d: SimpleNamespace(**d))

print(x.foo)
print(x.bar.x)
print(x.bar.y)

output:

3
1
2

from file:

JSON object: data.json

{
    "foo": 3,
    "bar": {
        "x": 1,
        "y": 2
    }
}
import json
from types import SimpleNamespace

with open("data.json") as fh:
    string = fh.read()

# Parse JSON into an object with attributes corresponding to dict keys.
x = json.loads(string, object_hook=lambda d: SimpleNamespace(**d))

print(x.foo)
print(x.bar.x)
print(x.bar.y)

output:

3
1
2

from requests

import json
from types import SimpleNamespace
import requests

r = requests.get('https://api.github.com/users/MilovanTomasevic')

# Parse JSON into an object with attributes corresponding to dict keys.
x = json.loads(r.text, object_hook=lambda d: SimpleNamespace(**d))

print(x.name)
print(x.company)
print(x.blog)

output:

Milovan Tomašević
NLB
milovantomasevic.com

For more beautiful and faster access to JSON response from API, take a look at this response.

Milovan Tomašević
  • 6,823
  • 1
  • 50
  • 42
14

You can use EasyDict library (doc):

EasyDict allows to access dict values as attributes (works recursively). A Javascript-like properties dot notation for python dicts.

USEAGE

>>> from easydict import EasyDict as edict
>>> d = edict({'foo':3, 'bar':{'x':1, 'y':2}})
>>> d.foo
3
>>> d.bar.x
1

>>> d = edict(foo=3)
>>> d.foo
3

[INSTALLATION]:

  • pip install easydict
Benyamin Jafari
  • 27,880
  • 26
  • 135
  • 150
12

All previous answers are correct, here is one more and easy way to do it. For example, create a Dict data structure to serialize and deserialize an object

(Notice None is Null in python and I'm intentionally using this to demonstrate how you can store null and convert it to json null)

import json
print('serialization')
myDictObj = { "name":"John", "age":30, "car":None }
##convert object to json
serialized= json.dumps(myDictObj, sort_keys=True, indent=3)
print(serialized)
## now we are gonna convert json to object
deserialization=json.loads(serialized)
print(deserialization)

enter image description here

R5498
  • 154
  • 1
  • 12
grepit
  • 21,260
  • 6
  • 105
  • 81
2

I create a recursive function to walk a nest dictionary representing the json structure.

  myjson={}
  myjson["Country"]= {"KR": { "id": "220", "name": "South Korea"}}
  myjson["Creative"]= {
                    "1067405": {
                        "id": "1067405",
                        "url": "https://cdn.gowadogo.com/559d1ba1-8d50-4c7f-b3f5-d80f918006e0.jpg"
                    },
                    "1067406": {
                        "id": "1067406",
                        "url": "https://cdn.gowadogo.com/3799a70d-339c-4ecb-bc1f-a959dde675b8.jpg"
                    },
                    "1067407": {
                        "id": "1067407",
                        "url": "https://cdn.gowadogo.com/180af6a5-251d-4aa9-9cd9-51b2fc77d0c6.jpg"
                    }
                }
   myjson["Offer"]= {
                    "advanced_targeting_enabled": "f",
                    "category_name": "E-commerce/ Shopping",
                    "click_lifespan": "168",
                    "conversion_cap": "50",
                    "currency": "USD",
                    "default_payout": "1.5"
                }

   json_data = json.dumps(myjson)

   #reverse back into a json

   paths=[]
   def walk_the_tree(inputDict,suffix=None):
       for key, value in inputDict.items():
            if isinstance(value, dict):
                if suffix==None:
                    suffix=key
                else:
                    suffix+=":"+key

                walk_the_tree(value,suffix)
            else:
                paths.append(suffix+":"+key+":"+value)
 walk_the_tree(myjson)
 print(paths)  

 #split and build your nested dictionary
 json_specs = {}
 for path in paths:
     parts=path.split(':')
     value=(parts[-1])
     d=json_specs
     for p in parts[:-1]:
         if p==parts[-2]:
             d = d.setdefault(p,value)
         else:
             d = d.setdefault(p,{})
    
 print(json_specs)        

 Paths:
 ['Country:KR:id:220', 'Country:KR:name:South Korea', 'Country:Creative:1067405:id:1067405', 'Country:Creative:1067405:url:https://cdn.gowadogo.com/559d1ba1-8d50-4c7f-b3f5-d80f918006e0.jpg', 'Country:Creative:1067405:1067406:id:1067406', 'Country:Creative:1067405:1067406:url:https://cdn.gowadogo.com/3799a70d-339c-4ecb-bc1f-a959dde675b8.jpg', 'Country:Creative:1067405:1067406:1067407:id:1067407', 'Country:Creative:1067405:1067406:1067407:url:https://cdn.gowadogo.com/180af6a5-251d-4aa9-9cd9-51b2fc77d0c6.jpg', 'Country:Creative:Offer:advanced_targeting_enabled:f', 'Country:Creative:Offer:category_name:E-commerce/ Shopping', 'Country:Creative:Offer:click_lifespan:168', 'Country:Creative:Offer:conversion_cap:50', 'Country:Creative:Offer:currency:USD', 'Country:Creative:Offer:default_payout:1.5']
Golden Lion
  • 3,840
  • 2
  • 26
  • 35
  • see for reversing paths to nested dictionaries (https://stackoverflow.com/questions/2738141/python-created-nested-dictionary-from-list-of-paths/2739972) – Golden Lion Feb 05 '21 at 21:29
0

you can create json file by using jsonCreater module

        `jsonCreator.createJson(dict,”fileName”,[“path”])`
Neil
  • 1
  • 1
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 01 '22 at 06:08