Я хотел бы определить подкласс dict, в частности, с настраиваемой сериализацией JSON. Проблема, с которой я сталкиваюсь, заключается в том, что, если я непосредственно создаю подкласс dict, то модуль json не входит в функцию 'default' при обнаружении экземпляров моего подкласса dict, минуя мою собственную сериализацию. Рассмотрим:
import collections
class MyDictA(dict):
# subclass of dict
def to_json(self):
return {
"items": dict(self),
"_type": self.__module__ + "." + self.__class__.__name__,
}
def __repr__(self):
return self.__class__.__name__ + "(" + repr(dict(self)) + ")"
class MyDictB(collections.MutableMapping):
# behaves like a dict, is not a dict
# can easily implement the remaining dict methods
def __getitem__(self, item):
return self.__dict__[item]
def __setitem__(self, key, value):
self.__dict__[key] = value
def to_json(self):
return {
"items": vars(self),
"_type": self.__module__ + "." + self.__class__.__name__,
}
def __repr__(self):
return self.__class__.__name__ + "(" + repr(self.__dict__) + ")"
def __iter__(self):
return self.__dict__.__iter__()
def __len__(self):
return len(self.__dict__)
def __delitem__(self, key):
del self.__dict__[key]
Я могу легко реализовать оставшиеся методы dict, так что MyDictB является заменой для dict, но это почему-то кажется непитоническим.
Теперь мы реализуем пользовательскую сериализацию:
import json
def my_default(obj):
if hasattr(obj, "to_json"):
return obj.to_json()
else:
return obj
Пример:
A = MyDictA()
A["foo"] = "bar"
B = MyDictB()
B["foo"] = "bar"
Результат:
>>> print(A)
MyDictA({'foo': 'bar'})
>>> print(B)
MyDictB({'foo': 'bar'})
>>> print(jsonA)
{"foo": "bar"}
>>> print(jsonB)
{"_type": "__main__.MyDictB", "items": {"foo": "bar"}}
Как видите, только MyDictB проходит через пользовательскую сериализацию 'my_default'; экземпляры MyDictA никогда не делают, так как они являются dict экземплярами.
проблема в модуле json заключается в том, что он обусловливает isinstance (obj, dict), см. Реализацию "_iterencode" в json / encoder.py.
Примечание:
>>> isinstance(A, collections.Mapping)
True
>>> isinstance(B, collections.Mapping)
True
>>> isinstance(A, dict)
True
>>> isinstance(B, dict)
False
Есть ли лучший способ заставить модуль json уважать мой подкласс dict?