如何使一个Python类序列化?
class FileItem:
def __init__(self, fname):
self.fname = fname
尝试序列化为JSON:
>>> import json
>>> x = FileItem('/foo/bar')
>>> json.dumps(x)
TypeError: Object of type 'FileItem' is not JSON serializable
如何使一个Python类序列化?
class FileItem:
def __init__(self, fname):
self.fname = fname
尝试序列化为JSON:
>>> import json
>>> x = FileItem('/foo/bar')
>>> json.dumps(x)
TypeError: Object of type 'FileItem' is not JSON serializable
当前回答
我最喜欢Lost Koder的方法。当我试图序列化成员/方法不可序列化的更复杂的对象时,我遇到了问题。这是我的实现,工作在更多的对象:
class Serializer(object):
@staticmethod
def serialize(obj):
def check(o):
for k, v in o.__dict__.items():
try:
_ = json.dumps(v)
o.__dict__[k] = v
except TypeError:
o.__dict__[k] = str(v)
return o
return json.dumps(check(obj).__dict__, indent=2)
其他回答
解决这个问题有很多方法。'ObjDict' (pip install object)是另一个。重点是提供像javascript一样的对象,它也可以像字典一样最好地处理从JSON加载的数据,但还有其他功能也很有用。这为原始问题提供了另一种解决方案。
下面是一个简单功能的简单解决方案:
.toJSON()方法
实现一个序列化器方法,而不是一个JSON可序列化类:
import json
class Object:
def toJSON(self):
return json.dumps(self, default=lambda o: o.__dict__,
sort_keys=True, indent=4)
所以你只需调用它来序列化:
me = Object()
me.name = "Onur"
me.age = 35
me.dog = Object()
me.dog.name = "Apollo"
print(me.toJSON())
将输出:
{
"age": 35,
"dog": {
"name": "Apollo"
},
"name": "Onur"
}
当我试图将Peewee的模型存储到PostgreSQL JSONField时,我遇到了这个问题。
在苦苦挣扎了一段时间后,这是通解。
我的解决方案的关键是浏览Python的源代码,并意识到代码文档(这里描述的)已经解释了如何扩展现有的json。转储以支持其他数据类型。
假设你现在有一个模型,其中包含一些不能序列化为JSON的字段,并且包含JSON字段的模型最初看起来是这样的:
class SomeClass(Model):
json_field = JSONField()
只需要像这样定义一个自定义JSONEncoder:
class CustomJsonEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, SomeTypeUnsupportedByJsonDumps):
return < whatever value you want >
return json.JSONEncoder.default(self, obj)
@staticmethod
def json_dumper(obj):
return json.dumps(obj, cls=CustomJsonEncoder)
然后像下面这样在你的JSONField中使用它:
class SomeClass(Model):
json_field = JSONField(dumps=CustomJsonEncoder.json_dumper)
键是上面的默认(self, obj)方法。对于每一个……你从Python收到的不是JSON序列化的投诉,只需添加代码来处理不可序列化的JSON类型(如Enum或datetime)
例如,下面是我如何支持从Enum继承的类:
class TransactionType(Enum):
CURRENT = 1
STACKED = 2
def default(self, obj):
if isinstance(obj, TransactionType):
return obj.value
return json.JSONEncoder.default(self, obj)
最后,使用上面实现的代码,您可以将任何Peewee模型转换为如下所示的json可序列化对象:
peewee_model = WhateverPeeweeModel()
new_model = SomeClass()
new_model.json_field = model_to_dict(peewee_model)
虽然上面的代码(在某种程度上)是针对Peewee的,但我认为:
它一般适用于其他orm (Django等) 如果你理解json。dump可以工作,这个解决方案一般也适用于Python(无ORM)
有任何问题,请在评论区留言。谢谢!
我喜欢Onur的答案,但会扩展到包括一个可选的toJSON()方法,用于对象序列化自己:
def dumper(obj):
try:
return obj.toJSON()
except:
return obj.__dict__
print json.dumps(some_big_object, default=dumper, indent=2)
这个函数使用递归迭代遍历字典的每个部分,然后调用非内置类型类的repr()方法。
def sterilize(obj):
object_type = type(obj)
if isinstance(obj, dict):
return {k: sterilize(v) for k, v in obj.items()}
elif object_type in (list, tuple):
return [sterilize(v) for v in obj]
elif object_type in (str, int, bool, float):
return obj
else:
return obj.__repr__()