In Python (without Pickle), Can Arbitrary JSON strings be Constructed Dynamically?
<p>In Python (2.7), is there a way to dynamically generate arbitrary JSON strings without using Pickle? </p>

<p>(To be clear, this inquiry dwells on constructing the JSON payload...long before invoking json.dumps().)</p>

<p>WHY?</p>

<p>Imagine you are undertaking a project that will involve interacting with several complex APIs (using JSON). </p>

<p>Each instance of EVERY JSON object that will be built and POSTed to the API(s) could well require a unique hierarchical structure (many, many levels of objects...a blizzard of ':', ',', '[]', '{}' ... you get the idea).</p>

<p>Other than instantiating a Python object and serializing it via Pickle, Is there an easier way to construct complex, arbitrary JSON strings that doesn't rely on hand/hard-coding a structure in place; such as this [poor] example:</p>

<pre><code>json_string = '{' + '"field_a": [ {' + '"id":' + id + '", "category":' + category . . . + '] }'
</code></pre>

<p>Your thoughts? Suggestions? Comments?</p>

<p><strong>Default JSON encoder</strong> is capable of creating a JSON from some basic types (e.g. int, str, list, dict), but it can't handle custom objects.</p>

<p>For example:</p>

<pre><code>json.dumps([1, 2, 3])  # this works: '[1, 2, 3]'

class A(object):
    def __init__(self):
        self.value1 = 1
        self.value2 = {'foo': ['bar', 'baz']}

json.dumps(A())  # this fails
</code></pre>

<h2>Custom JSON Encoders</h2>

<p>Luckily, json allows creating custom JSON encoders.</p>

<p>A custom JSON encoder does not have to create JSON. It just hs to convert an object into something that can be converted to JSON!</p>

<p>So, it is enough to create a dictionary.</p>

<p>The simplest solution is to use the <code>__dict__</code> - that will work for most custom classes, because <code>__dict__</code> contains a dictionary of all member variables, and dictionaries can be encoded into JSON by the built-in encoder:</p>

<pre><code>class DictJsonEncoder(json.JSONEncoder):
    def default(self, obj):
        return obj.__dict__

json.dumps(a, cls=DictJsonEncoder)  # '{"value2": {"foo": ["bar", "baz"]}, "value1": 1}'
</code></pre>

<h2>A More Flexible Solution</h2>

<p>For more flexibility, don't always use <code>__dict__</code> (but use it as the default).</p>

<p>A common pattern is to implement <code>__json__</code> method which does what is needed and use that when available:</p>

<pre><code>class MyJsonEncoder(json.JSONEncoder):
    def default(self, obj):
        if hasattr(obj, '__json__'):
            return obj.__json__()
        else:
            return super(MyJsonEncoder, self).default(obj)
</code></pre>

<p>Then implement the default <code>__json__</code> method which returns <code>__dict__</code>:</p>

<pre><code>class JsonCapable(object):
    def __json__(self):
        return self.__dict__

class A(JsonCapable):
    def __init__(self):
        self.value1 = 1
        self.value2 = {'foo': ['bar', 'baz']}

    # For special needs, override __json__ here

json.dumps(a, cls=MyJsonEncoder)  # '{"value2": {"foo": ["bar", "baz"]}, "value1": 1}'
</code></pre>

<hr>

<p>Alternatively, the encoder could use <code>__json__</code> if it finds it and <code>__dict__</code> as backup. Then there is no need for a <code>JsonCapable</code> class.</p>

python json python-2.7 pickle