Skip to content

JSON (JAVASCRIPT OBJECT NOTATION)

Irvine Sunday edited this page Feb 16, 2023 · 5 revisions

JSON (JavaScript Object Notation) is a lightweight data-interchange format that is easy for humans to read and write and easy for machines to parse and generate.
Serialization is the process of converting an object's state to a format that can be stored or transmitted
Deserialization is the process of creating an object from a stored or transmitted format.
The json module, which is built into Python's standard library, provides functions for working with JSON.
In Python, JSON can be used in two ways:

1. json.dumps() AND json.loads() METHODS


The json.dumps() method can be used to convert a Python object into a JSON string. (Serialization)

The json.loads() method can be used to convert a JSON string into a Python object.(Deserialization)
In deserialization process, the json module will try to parse the input JSON string and convert it into the most appropriate Python data types, but if the JSON string contains elements that don't have an obvious matching Python data type, it will raise an exception.

import json

# a Python object (dict):
x = {
  "name": "John",
  "age": 30,
  "city": "New York"
}

# convert into JSON:
y = json.dumps(x)

# the result is a JSON string:
print(y)

#parse back to python 
z = json.loads(y)
print(z)

2. json.load() AND json.dump() METHODS


These functions are used to read and write the json files directly.

import json

# a Python object (dict):
x = {
  "name": "John",
  "age": 30,
  "city": "New York"
}

# Serialize the python object to json file 
with open("file.json", "w") as outfile:
    json.dump(x, outfile)
    
# Deserialize json data from file
with open("file.json", "r") as json_file:
    data = json.load(json_file)

N/B: JSON is a language-independent data format, and as such it has a limited set of data types that can be represented. JSON supports the following data types:

  • Numbers (integer and floating-point)
  • Strings (double-quoted Unicode with backslash escapement)
  • Booleans (true and false)
  • Arrays (ordered sequences of values enclosed in square brackets)
  • Objects (collections of key-value pairs enclosed in curly braces)

Python also has additional data types that are not supported by JSON, such as tuples, complex numbers, sets, and bytes. So, when you convert a Python object to a JSON string, you will lose information about the non-supported data types. Also, When you convert a Python object to a JSON string and then back to a Python object, you might lose information about the original object's type. For example, a Python list and tuple would both be represented as a JSON array and would not be differentiated upon deserialization back to python object.

3. EXCEPTIONS


  • json.decoder.JSONDecodeError: This exception is raised when there is an error decoding a JSON document. This can happen when the document is not well-formed, such as if it contains mismatched brackets or unescaped special characters. It also happens when the JSON document is not in the expected format, such as when it has the wrong number of keys or values.

  • TypeError: This exception can be raised when an object of the wrong type is passed to the json.dumps() or json.dump() method. For example, if you try to serialize a Python tuple, which is not supported by JSON, this exception will be raised. It can also occur when trying to deserialize json objects that cannot be mapped to python object.

  • FileNotFoundError : This exception can be raised when you are trying to read/write json file and the file is not found.

  • UnicodeDecodeError : this error can be raised when the json file contains unexpected encoding format, it might happens when file contain non-ascii characters, and trying to read it as ascii.

It's a good idea to handle these exceptions in your code, so that your program can gracefully handle errors and provide feedback to the user. You can use try-except block to handle these exceptions and take appropriate action. For example:

import json

try:
    with open("file.json", "r") as json_file:
        data = json.load(json_file)
    print(data)
except json.decoder.JSONDecodeError as e:
    print(f"Error decoding JSON: {e}")
except FileNotFoundError as e:
    print(f"Error: {e}")
except Exception as e:
    print(f"An unexpected error occurred: {e}")

4. SEPARATORS, SORTKEYS AND INDET


The json.dumps() method in Python's standard library allows you to specify several parameters to customize the behavior of the serialization process.

  • The separators parameter allows you to specify the separator characters to use between items in the JSON output. By default, json.dumps() uses a comma to separate items in an array and a colon to separate keys from values in an object.
    You can use the separators parameter to specify different separator characters.
    You can use the separators parameter to remove the whitespaces from the output, which can be useful for creating more compact JSON strings.
import json

x = {
  "name": "John",
  "age": 30,
  "city": "New York"
}

y = json.dumps(x, separators=(',', ':'))
print(y)
  • The sort_keys parameter allows you to specify whether the keys in the JSON output should be sorted. By default, the keys in the JSON output will be in the same order as they appear in the original Python object. If you set sort_keys to True, the keys will be sorted alphabetically.
import json

x = {
  "name": "John",
  "age": 30,
  "city": "New York"
}

y = json.dumps(x, sort_keys=True)
print(y)

By default, json.dump() uses the same parameters as json.dumps() so you can use these parameters in the same way when writing json to a file.

  • The indent parameter is used to customize the format of the output JSON. This parameter controls the number of spaces to use for indentation, similar to the way python uses indentation to format the code.
    When you set indent to a positive integer, the JSON output will be formatted with that many spaces of indentation for each level of nesting. By default indent is not set and json output is not formatted.
import json

x = {
  "name": "John",
  "age": 30,
  "city": "New York",
  "address": {
    "street": "5th Ave",
    "zipcode": "10019"
  }
}

y = json.dumps(x, indent=4)
print(y)

The output will be formatted with 4 spaces of indentation for each level of nesting, making it more human-readable.
By default, json.dump() uses the same parameters as json.dumps(), so you can use this parameter in the same way when writing json to a file.

import json

x = {
  "name": "John",
  "age": 30,
  "city": "New York",
  "address": {
    "street": "5th Ave",
    "zipcode": "10019"
  }
}

with open("file.json", "w") as outfile:
    json.dump(x, outfile, indent=4)

It's important to note that when you set indent to a positive value, the json output will be more readable, but also larger in size. It can be useful when the json will be read mostly by humans, and it's important to understand the structure of the json data, while it can be a drawback when the json needs to be transmitted or stored.

5. OTHER METHODS


  • json.JSONEncoder: An extensible JSON encoder for Python data structures.
    he json.JSONEncoder class in Python's standard library provides a way to customize the behavior of the json.dumps() method. It allows you to define custom encoding logic for specific data types, or to change the way that built-in data types are encoded.

By default, the json.dumps() method will call the JSONEncoder's default() method to encode any object that is not one of the built-in JSON data types (such as numbers, strings, booleans, lists, and dictionaries). The default() method is defined to raise a TypeError, so if you want to encode a custom data type, you'll need to either define a custom JSONEncoder subclass or pass an instance of one as the cls parameter to json.dumps().

Here's an example of how to use a custom JSONEncoder subclass to encode a Python datetime object:

import json
from datetime import datetime

class DatetimeEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.isoformat()
        return super().default(obj)

x = {
    "created_at": datetime.now()
}

y = json.dumps(x, cls=DatetimeEncoder)
print(y)

In this example, a new class DatetimeEncoder is created by subclassing json.JSONEncoder, and the default() method is overridden to check if the object being encoded is an instance of datetime, in that case it returns the isoformat representation of the datetime, otherwise it falls back to the default behavior of the JSONEncoder class.

In this way, when you pass an instance of this class to the cls parameter of json.dumps() method, it will use the custom default method to encode the datetime object, otherwise it will fallback to the default JSONEncoder class.