You could always construct such a string value by hand.
On the other hand, one can make the CPython json
module to encode duplicate keys. This is very tricky in Python 2 because json
module does not respect duck-typing at all.
The straightforward solution would be to inherit from collections.Mapping
- well you can't, since "MyMapping
is not a JSON serializable."
Next one tries to subclass a dict
- well, but if json.dumps
notices that the type is dict
, it skips from calling __len__
, and sees the underlying dict
directly - if it is empty, {}
is output directly, so clearly if we fake the methods, the underlying dictionary must not be empty.
The next source of joy is that actually __iter__
is called, which iterates keys; and for each key, the __getitem__
is called, so we need to remember what is the corresponding value to return for the given key... thus we arrive to a very ugly solution for Python 2:
class FakeDict(dict):
def __init__(self, items):
# need to have something in the dictionary
self['something'] = 'something'
self._items = items
def __getitem__(self, key):
return self.last_val
def __iter__(self):
def generator():
for key, value in self._items:
self.last_val = value
yield key
return generator()
In CPython 3.3+ it is slightly easier... no, collections.abc.Mapping
does not work, yes, you need to subclass a dict
, yes, you need to fake that your dictionary has content... but the internal JSON encoder calls items
instead of __iter__
and __getitem__
!
Thus on Python 3:
import json
class FakeDict(dict):
def __init__(self, items):
self['something'] = 'something'
self._items = items
def items(self):
return self._items
print(json.dumps(FakeDict([('a', 1), ('a', 2)])))
prints out
{"a": 1, "a": 2}