Skip to content

Instantly share code, notes, and snippets.

@acdha
Last active January 21, 2023 01:33
Show Gist options
  • Save acdha/e5392a4d41396eeeab0c7202e683a6e4 to your computer and use it in GitHub Desktop.
Save acdha/e5392a4d41396eeeab0c7202e683a6e4 to your computer and use it in GitHub Desktop.
Example of how to exclude Nones from JSON-encoded output, optionally destructively
#!/usr/bin/env python3
"""
Example of how to non-destructively remove None values from an object before
JSON serialization
"""
import json
def filter_nones(obj):
"""
Given a JSON-serializable object, return a copy without elements which have
a value of None.
"""
if isinstance(obj, list):
# This version may or may not be easier to read depending on your
# preferences:
# return list(filter(None, map(remove_nones, obj)))
# This version uses a generator expression to avoid computing a full
# list only to immediately walk it again:
filtered_values = (filter_nones(j) for j in obj)
return [i for i in filtered_values if i is not None]
elif isinstance(obj, dict):
filtered_items = ((i, filter_nones(j)) for i, j in obj.items())
return {k: v for k, v in filtered_items if v is not None}
else:
return obj
def remove_nones(obj):
"""
Given a JSON-serializable object, modify it in place to remove elements
which have a value of None
"""
if isinstance(obj, list):
# We can't use list.remove() while iterating because that will cause the
# next element in the list to be skipped.
# Slice assignment alters the list in-place in case there are any other
# references to it:
# for i in obj:
# remove_nones(i)
# obj[:] = [i for i in obj if i is not None]
# … or we can walk the list in reverse to avoid a second pass:
for i in range(len(obj) - 1, -1, -1):
v = obj[i]
if v is None:
obj.pop(i)
else:
remove_nones(v)
elif isinstance(obj, dict):
# We're forced to create a list first to avoid an exception caused by
# changing the dictionary size while iterating:
for k, v in list(obj.items()):
if v is None:
obj.pop(k)
else:
remove_nones(v)
resp = {
"scalar": "test",
"list": ["foo", None, "bar"],
"nested_dict": {
"a": 1,
"b": ["test", None, "test2"],
"d": None,
"e": [
None,
{
"k": None,
"a": "b",
},
],
},
"scalar2": None,
"nested_list": [
"foo",
[None],
["bar", "baaz"],
],
}
print(json.dumps(resp, indent=4))
print(json.dumps(filter_nones(resp), indent=4))
remove_nones(resp)
print(json.dumps(resp, indent=4))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment