我正在编写一个带有Tornado后端的webapp,当然还有前端的javascript和jquery,所以我使用标准库中的内置json模块来序列化前端的对象。我已经开始为我的类编写一个自定义的JSONEncoder,但后来我发现我只能编写一个非常简单的通用对象编码器:
class ObjectEncoder(json.JSONEncoder):
def default(self, obj):
return vars(obj)
它似乎工作得很好,所以我想知道为什么这不包含在模块中,如果这种技术有缺点。如果它与check_circular很好地合作,我没有进行实验,但我没有理由相信它没有。
对我怀疑的任何评论?否则,我认为这种技术可能对某些人有用,因为我没有通过搜索找到它(诚然,快速的)。
编辑:这是一个示例,尽可能简单,以显示json模块的行为:
>>> import json
>>> class Foo:
... def __init__(self):
... self.bar = 'bar'
...
>>> foo = Foo()
>>> json.dumps(foo)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.5/json/__init__.py", line 230, in dumps
return _default_encoder.encode(obj)
File "/usr/lib/python3.5/json/encoder.py", line 198, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python3.5/json/encoder.py", line 256, in iterencode
return _iterencode(o, 0)
File "/usr/lib/python3.5/json/encoder.py", line 179, in default
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <__main__.Foo object at 0x7f14660236d8> is not JSON serializable
>>> class ObjectEncoder(json.JSONEncoder):
... def default(self, obj):
... return vars(obj)
...
>>> json.dumps(foo, cls=ObjectEncoder)
'{"bar": "bar"}'
答案 0 :(得分:1)
vars(obj)
是obj.__dict__
的语法糖,因此它不适用于没有__dict__
的任何对象。这包括以下内容:
__slots__
(没有__dict__
个插槽)以减少内存使用量tp_dict
广告位的内置类型的对象更糟糕的是,存在中间情况,其中某些属性在__dict__
上设置,而其他属性则不是(例如,某些级别使用__slots__
的类层次结构,但是其他级别没有使用__slots__
并且依赖于隐式__dict__
)。在这样的情况下,你不会得到错误让你知道出了什么问题,你只是序列化对象状态的__dict__
部分并默默地忽略其余部分。
如果界面使用@property
s,您会遇到类似的问题;它们像属性一样被使用,但它们不在实例__dict__
上,因此您要么完全丢失信息(如果没有隐藏的基础属性),要么序列化& #34;错误&#34; value(内部名称,而不是作为@property
公开的API名称)。
简而言之,通过尝试猜测这样的正确行为,很多事情可能会出现严重错误,这就是为什么Python的Zen(在交互式终端中输入import this
来查看它)包括以下内容:
错误绝不应该以无声方式传递。
和
面对模棱两可,拒绝猜测的诱惑。
除了这些错误之外,还存在可逆性的一般问题。此表单的常规编码器在定义上无法由常规解码器处理(因为您丢失了所有类型信息)。提供一种丢失重要信息的简便方法是......次优。