如何使可序列化的JSON类


832

如何使Python类可序列化?

一个简单的类:

class FileItem:
    def __init__(self, fname):
        self.fname = fname

我应该怎么做才能获得输出:

>>> import json

>>> my_file = FileItem('/foo/bar')
>>> json.dumps(my_file)
TypeError: Object of type 'FileItem' is not JSON serializable

没有错误


30
不幸的是,所有答案似乎都回答了“我如何序列化一个类?”这个问题。而不是动作问题“如何使类可序列化?” 这些答案假定您自己进行序列化,而不是将对象传递给对其进行序列化的其他模块。
凯尔·德莱尼

如果您使用的是Python3.5 +,则可以使用jsons。它将您的对象(及其所有属性递归地)转换成字典。 import jsons看到下面的答案-它工作得很好
tswaehn

Answers:


551

您对预期的输出有想法吗?例如这样做吗?

>>> f  = FileItem("/foo/bar")
>>> magic(f)
'{"fname": "/foo/bar"}'

在这种情况下,您只能致电json.dumps(f.__dict__)

如果您想要更多的自定义输出,则必须继承JSONEncoder并实现自己的自定义序列化。

有关一个简单的示例,请参见下文。

>>> from json import JSONEncoder
>>> class MyEncoder(JSONEncoder):
        def default(self, o):
            return o.__dict__    

>>> MyEncoder().encode(f)
'{"fname": "/foo/bar"}'

然后,将该类json.dumps()作为clskwarg 传递给方法:

json.dumps(cls=MyEncoder)

如果你也想解码,那么你将有一个自定义供应object_hookJSONDecoder类。例如

>>> def from_json(json_object):
        if 'fname' in json_object:
            return FileItem(json_object['fname'])
>>> f = JSONDecoder(object_hook = from_json).decode('{"fname": "/foo/bar"}')
>>> f
<__main__.FileItem object at 0x9337fac>
>>> 

44
使用__dict__并非在所有情况下都有效。如果在实例化对象后尚未设置属性,则__dict__可能未完全填充。在上面的示例中,您可以,但是,如果您还具有要编码的类属性,则__dict__除非在类__init__调用中或在实例化对象后通过其他方式对其进行了修改,否则不会列出这些属性。
克里斯·哈迪

8
+1,但from_json()用作对象挂钩的函数应具有一条else: return json_object语句,因此它也可以处理常规对象。
jogojapan

8
__dict__如果您__slots__在新样式的类上使用,则@KrisHardy 也将不起作用。
badp

7
您可以使用上述自定义JSONEncoder方法来创建自定义协议,例如检查__json_serializable__方法的存在并调用它以获得对象的JSON可序列化表示形式。这将是与其他Python模式,如饲养__getitem____str____eq__,和__len__
jpmc26 2015年

5
__dict__也不会递归工作,例如,如果您的对象的属性是另一个对象。
Neel

633

这是一个简单功能的简单解决方案:

.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"
}

82
非常有限。如果您有一个dict {“ foo”:“ bar”,“ baz”:“ bat”},它将轻松地序列化为JSON。相反,如果您有{“ foo”:“ bar”,“ baz”:MyObject()},则不能。理想的情况是将嵌套对象递归而不是显式地序列化为JSON。
Mark E. Haase 2013年

30
它仍然可以工作。你不见了o.__dict___。尝试您自己的示例: class MyObject(): def __init__(self): self.prop = 1 j = json.dumps({ "foo": "bar", "baz": MyObject() }, default=lambda o: o.__dict__)
OnurYıldırım2013年

14
这种解决方案是可逆的吗?即从json重建对象容易吗?
豪尔赫·雷涛

2
@JCLeitão否。您可以有两个具有相同字段的不同类。该类的对象a和b(可能具有相同的属性)将具有相同的a.__dict__/ b.__dict__
Martin Thoma 2015年

7
这不适用于datetime.datetime实例。它引发以下错误:'datetime.datetime' object has no attribute '__dict__'
Bruno Finger

171

对于更复杂的类,您可以考虑使用jsonpickle工具:

jsonpickle是一个Python库,用于将复杂的Python对象与JSON进行序列化和反序列化。

用于将Python编码为JSON的标准Python库(例如stdlib的json,simplejson和demjson)只能处理具有直接JSON等效项的Python原语(例如,字典,列表,字符串,整数等)。jsonpickle建立在这些库之上,并允许将更复杂的数据结构序列化为JSON。jsonpickle具有高度的可配置性和可扩展性,允许用户选择JSON后端并添加其他后端。

(链接到PyPi上的jsonpickle)


31
来自C#,这就是我的期望。一个简单的班轮,不会使课程混乱。
Jerther 2015年

2
jsonpickle很棒。它完美地适用于具有多个级别级别的巨大,复杂,凌乱的对象
wisbucky

有没有将其保存到文件的正确方法的示例?该文档仅显示如何编码和解码jsonpickle对象。而且,这不能解码包含熊猫数据帧的命令的命令。
user5359531

3
@ user5359531您可以使用obj = jsonpickle.decode(file.read())file.write(jsonpickle.encode(obj))
Kilian Batzner '17

1
专门针对django的问题:使用jsonpickle序列化会话数据是否具有与pickle相同的漏洞?(如docs.djangoproject.com/en/1.11/topics/http/sessions/…所述)?
Paul Bormans

89

大多数答案都涉及将对json.dumps()的调用更改为并非总是可能或不希望的(例如,它可能发生在框架组件内部)。

如果您希望能够原样调用 json.dumps(obj),那么一个简单的解决方案就是从dict继承:

class FileItem(dict):
    def __init__(self, fname):
        dict.__init__(self, fname=fname)

f = FileItem('tasks.txt')
json.dumps(f)  #No need to change anything here

如果您的类只是基本数据表示形式,则此方法有效,对于棘手的事情,您始终可以显式设置键。


2
这确实是一个不错的解决方案:)我相信我的情况是这样。好处:通过使对象具有init类来传达对象的“形状”,它固有地可序列化,并且可以解释为repr
PascalVKooten '16

1
虽然仍然缺少“点访问” :(
PascalVKooten

2
嗯,这似乎有效!谢谢,不确定为什么这不是可接受的答案。我完全同意更改dumps并不是一个好的解决方案。顺便说一句,在大多数情况下,您可能希望将dict继承与委托一起拥有,这意味着您将dict在类内拥有一些type属性,然后您将把此属性作为参数传递给初始化,例如super().__init__(self.elements)
cglacet

47

我喜欢Onur的答案,但会扩展为包括一个可选toJSON()方法,以使对象自行序列化:

def dumper(obj):
    try:
        return obj.toJSON()
    except:
        return obj.__dict__
print json.dumps(some_big_object, default=dumper, indent=2)

我发现这是在使用现有json.dumps处理和引入自定义处理之间的最佳平衡。谢谢!
丹尼尔·巴克马斯特

12
我真的很喜欢这样;但是try-catch可能不会做类似if 'toJSON' in obj.__attrs__():...避免静默失败(如果toJSON()由于其他原因而失败),则可能导致数据损坏。
thclark

39

另一个选择是将JSON转储包装在其自己的类中:

import json

class FileItem:
    def __init__(self, fname):
        self.fname = fname

    def __repr__(self):
        return json.dumps(self.__dict__)

或者,甚至更好的是,从类中继承FileItem JsonSerializable类:

import json

class JsonSerializable(object):
    def toJson(self):
        return json.dumps(self.__dict__)

    def __repr__(self):
        return self.toJson()


class FileItem(JsonSerializable):
    def __init__(self, fname):
        self.fname = fname

测试:

>>> f = FileItem('/foo/bar')
>>> f.toJson()
'{"fname": "/foo/bar"}'
>>> f
'{"fname": "/foo/bar"}'
>>> str(f) # string coercion
'{"fname": "/foo/bar"}'

2
嗨,我不太喜欢这种“自定义编码器”方法,如果您可以将您的json序列化为更好,那会更好。我尝试,尝试尝试,一无所获。有任何想法如何做到这一点。事实是json模块针对内置的python类型测试您的类,甚至说要为自定义类创建您的编码器:)。可以伪造吗?所以我可以对我的班级做些什么,使其表现得像json模块的简单列表一样?我尝试子类检查实例检查,但什么也没有。
Bojan Radojevic

@ADRENALIN如果所有类属性值都是可序列化的,并且您不介意黑客,则可以从主类型(大概是dict)继承。您也可以使用jsonpickle或json_tricks或其他东西代替标准编码器(仍然是自定义编码器,但不需要编写或调用编码器)。前者将实例腌制,后者将其存储为属性的字典,您可以通过实现__json__encode__/ 进行更改__json_decode__(公开:我制作了最后一个)。
标记

30

只需将to_json方法添加到您的类中,如下所示:

def to_json(self):
  return self.message # or how you want it to be serialized

并将此代码(来自此答案添加到所有内容的顶部:

from json import JSONEncoder

def _default(self, obj):
    return getattr(obj.__class__, "to_json", _default.default)(obj)

_default.default = JSONEncoder().default
JSONEncoder.default = _default

导入时,它将对猴子json模块进行猴子补丁处理,因此JSONEncoder.default()自动检查特殊的“ to_json()”方法,并在找到后使用该方法对对象进行编码。

就像Onur所说的一样,但是这次您不必更新json.dumps()项目中的每个项目。


6
太谢谢了!这是唯一允许我做我想做的答案:能够序列化对象而无需更改现有代码。其他方法大多对我不起作用。该对象是在第三方库中定义的,并且序列化代码也是第三方的。更改它们将很尴尬。用你的方法,我只需要做TheObject.to_json = my_serializer
Wu

24

前几天,我遇到了这个问题,并为Python对象实现了一个更通用的Encoder版本,可以处理嵌套对象继承的字段

import json
import inspect

class ObjectEncoder(json.JSONEncoder):
    def default(self, obj):
        if hasattr(obj, "to_json"):
            return self.default(obj.to_json())
        elif hasattr(obj, "__dict__"):
            d = dict(
                (key, value)
                for key, value in inspect.getmembers(obj)
                if not key.startswith("__")
                and not inspect.isabstract(value)
                and not inspect.isbuiltin(value)
                and not inspect.isfunction(value)
                and not inspect.isgenerator(value)
                and not inspect.isgeneratorfunction(value)
                and not inspect.ismethod(value)
                and not inspect.ismethoddescriptor(value)
                and not inspect.isroutine(value)
            )
            return self.default(d)
        return obj

例:

class C(object):
    c = "NO"
    def to_json(self):
        return {"c": "YES"}

class B(object):
    b = "B"
    i = "I"
    def __init__(self, y):
        self.y = y

    def f(self):
        print "f"

class A(B):
    a = "A"
    def __init__(self):
        self.b = [{"ab": B("y")}]
        self.c = C()

print json.dumps(A(), cls=ObjectEncoder, indent=2, sort_keys=True)

结果:

{
  "a": "A", 
  "b": [
    {
      "ab": {
        "b": "B", 
        "i": "I", 
        "y": "y"
      }
    }
  ], 
  "c": {
    "c": "YES"
  }, 
  "i": "I"
}

1
虽然这有点旧。.我正面临一些循环导入错误。因此,return obj我没有在最后一行中这样做return super(ObjectEncoder, self).default(obj)。参考这里
SomeTypeFoo 17-4-11

23

如果您使用的是Python3.5 +,则可以使用jsons。它将把您的对象(及其所有属性递归地)转换成字典。

import jsons

a_dict = jsons.dump(your_object)

或者,如果您想要一个字符串:

a_str = jsons.dumps(your_object)

或者如果您的班级实施了jsons.JsonSerializable

a_dict = your_object.json

3
如果您能够使用Python 3.7+,我发现将python类转换为dict和JSON字符串(反之亦然)的最干净的解决方案是将jsons库与dataclasses混合使用。到目前为止,对我有好处!
Ruluk

3
这是一个外部库,未内置在标准Python安装中。
Noumenon

仅适用于具有广告属性的类
yehudahs 19/12/3

可以,但是不需要使用slot。仅当根据特定类的签名进行转储时,才需要插槽。在即将发布的版本1.1.0中也不再如此。
RH

11
import simplejson

class User(object):
    def __init__(self, name, mail):
        self.name = name
        self.mail = mail

    def _asdict(self):
        return self.__dict__

print(simplejson.dumps(User('alice', 'alice@mail.com')))

如果使用标准json,则需要定义一个default函数

import json
def default(o):
    return o._asdict()

print(json.dumps(User('alice', 'alice@mail.com'), default=default))

2
我通过使用lambda删除_asdict函数来简化了这一过程 json.dumps(User('alice', 'alice@mail.com'), default=lambda x: x.__dict__)
JustEngland

8

json在可以打印的对象方面受到限制,并且jsonpickle(您可能需要pip install jsonpickle)在不能缩进文本方面受到限制。如果您想检查无法更改其类的对象的内容,我仍然找不到比以下方法更直接的方法:

 import json
 import jsonpickle
 ...
 print  json.dumps(json.loads(jsonpickle.encode(object)), indent=2)

注意:他们仍然无法打印对象方法。


6

此类可以解决问题,它将对象转换为标准json。

import json


class Serializer(object):
    @staticmethod
    def serialize(object):
        return json.dumps(object, default=lambda o: o.__dict__.values()[0])

用法:

Serializer.serialize(my_object)

python2.7和工作python3


我最喜欢这种方法。尝试序列化其成员/方法无法序列化的更复杂对象时,我遇到了问题。这是我的实现,可以在更多对象上使用:```类Serializer(object):@staticmethod def serialize(obj):def check(o):for o,__ dict __。items()中的k,v:try:_ = json .dumps(v)o .__ dict __ [k] = v,但TypeError除外:o .__ dict __ [k] = str(v)返回o返回json.dumps(check(obj).__ dict__,indent = 2)```
将Charlton

4
import json

class Foo(object):
    def __init__(self):
        self.bar = 'baz'
        self._qux = 'flub'

    def somemethod(self):
        pass

def default(instance):
    return {k: v
            for k, v in vars(instance).items()
            if not str(k).startswith('_')}

json_foo = json.dumps(Foo(), default=default)
assert '{"bar": "baz"}' == json_foo

print(json_foo)

From doc:参数default(obj)是一个应返回obj的可序列化版本或引发TypeError的函数。默认default只是引发TypeError。
luckydonald

4

jaraco给出了一个非常简洁的答案。我需要修复一些小问题,但这可行:

# Your custom class
class MyCustom(object):
    def __json__(self):
        return {
            'a': self.a,
            'b': self.b,
            '__python__': 'mymodule.submodule:MyCustom.from_json',
        }

    to_json = __json__  # supported by simplejson

    @classmethod
    def from_json(cls, json):
        obj = cls()
        obj.a = json['a']
        obj.b = json['b']
        return obj

# Dumping and loading
import simplejson

obj = MyCustom()
obj.a = 3
obj.b = 4

json = simplejson.dumps(obj, for_json=True)

# Two-step loading
obj2_dict = simplejson.loads(json)
obj2 = MyCustom.from_json(obj2_dict)

# Make sure we have the correct thing
assert isinstance(obj2, MyCustom)
assert obj2.__dict__ == obj.__dict__

请注意,我们需要两个步骤进行加载。目前,该__python__属性尚未使用。

这有多普遍?

使用AlJohri的方法,我检查了方法的普及程度:

序列化(Python-> JSON):

反序列化(JSON-> Python):


4

这对我来说效果很好:

class JsonSerializable(object):

    def serialize(self):
        return json.dumps(self.__dict__)

    def __repr__(self):
        return self.serialize()

    @staticmethod
    def dumper(obj):
        if "serialize" in dir(obj):
            return obj.serialize()

        return obj.__dict__

然后

class FileItem(JsonSerializable):
    ...

log.debug(json.dumps(<my object>, default=JsonSerializable.dumper, indent=2))

3

如果您不介意为其安装软件包,则可以使用json-tricks

pip install json-tricks

在此之后,你只需要导入dump(s)json_tricks替代JSON,它通常会工作:

from json_tricks import dumps
json_str = dumps(cls_instance, indent=4)

这会给

{
        "__instance_type__": [
                "module_name.test_class",
                "MyTestCls"
        ],
        "attributes": {
                "attr": "val",
                "dct_attr": {
                        "hello": 42
                }
        }
}

基本上就是这样!


总的来说,这会很好。有一些例外,例如,如果发生了特殊情况__new__,或者发生了更多的元类魔术。

显然,加载也可以(否则有什么意义):

from json_tricks import loads
json_str = loads(json_str)

这确实假定module_name.test_class.MyTestCls可以导入并且没有以不兼容的方式进行更改。您将获得一个实例,而不是字典或其他内容,它应该与您转储的副本相同。

如果要自定义某些东西的序列化方法,可以向类中添加特殊方法,如下所示:

class CustomEncodeCls:
        def __init__(self):
                self.relevant = 42
                self.irrelevant = 37

        def __json_encode__(self):
                # should return primitive, serializable types like dict, list, int, string, float...
                return {'relevant': self.relevant}

        def __json_decode__(self, **attrs):
                # should initialize all properties; note that __init__ is not called implicitly
                self.relevant = attrs['relevant']
                self.irrelevant = 12

例如,它仅序列化部分属性参数。

作为免费赠品,您可以获得numpy数组(日期)的反序列化,日期和时间,有序映射以及在json中包含注释的功能。

免责声明:我创建了json_tricks,因为我和您有同样的问题。


1
我刚刚测试了json_tricks,它可以美化(在2019年)。
pauljohn32 '19

2

jsonweb似乎是对我最好的解决方案。参见http://www.jsonweb.info/en/latest/

from jsonweb.encode import to_object, dumper

@to_object()
class DataModel(object):
  def __init__(self, id, value):
   self.id = id
   self.value = value

>>> data = DataModel(5, "foo")
>>> dumper(data)
'{"__type__": "DataModel", "id": 5, "value": "foo"}'

它是否适合嵌套对象?包括解码和编码
Simone Zandara 2015年

1

这是我的3美分...
这演示了一个类似树的python对象的显式json序列化。
注意:如果您实际上想要这样的代码,则可以使用扭曲的FilePath类。

import json, sys, os

class File:
    def __init__(self, path):
        self.path = path

    def isdir(self):
        return os.path.isdir(self.path)

    def isfile(self):
        return os.path.isfile(self.path)

    def children(self):        
        return [File(os.path.join(self.path, f)) 
                for f in os.listdir(self.path)]

    def getsize(self):        
        return os.path.getsize(self.path)

    def getModificationTime(self):
        return os.path.getmtime(self.path)

def _default(o):
    d = {}
    d['path'] = o.path
    d['isFile'] = o.isfile()
    d['isDir'] = o.isdir()
    d['mtime'] = int(o.getModificationTime())
    d['size'] = o.getsize() if o.isfile() else 0
    if o.isdir(): d['children'] = o.children()
    return d

folder = os.path.abspath('.')
json.dump(File(folder), sys.stdout, default=_default)

1

当我尝试将Peewee的模型存储到PostgreSQL中时遇到了这个问题 JSONField

经过一段时间的努力,这是一般的解决方案。

我的解决方案的关键是浏览Python的源代码,并意识到代码文档(在此描述)已经解释了如何扩展现有的json.dumps以支持其他数据类型。

假设您当前有一个模型,其中包含一些无法序列化为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)

关键是default(self, obj)上面的方法。对于... is not JSON serializable您从Python收到的每一个投诉,只需添加代码来处理从unserializable-to-JSON类型(例如Enumdatetime

例如,这是我如何支持从继承的类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,但是我认为:

  1. 通常适用于其他ORM(例如Django等)
  2. 另外,如果您了解其json.dumps工作原理,那么该解决方案通常也适用于Python(无ORM)

如有任何疑问,请发表在评论部分。谢谢!


1

此函数使用递归遍历字典的每个部分,然后调用非内置类型的类的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):
        return obj
    else:
        return obj.__repr__()


0

我想出了自己的解决方案。使用此方法,传递任何文档(dictlistObjectId等)进行序列化。

def getSerializable(doc):
    # check if it's a list
    if isinstance(doc, list):
        for i, val in enumerate(doc):
            doc[i] = getSerializable(doc[i])
        return doc

    # check if it's a dict
    if isinstance(doc, dict):
        for key in doc.keys():
            doc[key] = getSerializable(doc[key])
        return doc

    # Process ObjectId
    if isinstance(doc, ObjectId):
        doc = str(doc)
        return doc

    # Use any other custom serializting stuff here...

    # For the rest of stuff
    return doc

0

我选择使用装饰器解决datetime对象序列化问题。这是我的代码:

#myjson.py
#Author: jmooremcc 7/16/2017

import json
from datetime import datetime, date, time, timedelta
"""
This module uses decorators to serialize date objects using json
The filename is myjson.py
In another module you simply add the following import statement:
    from myjson import json

json.dumps and json.dump will then correctly serialize datetime and date 
objects
"""

def json_serial(obj):
    """JSON serializer for objects not serializable by default json code"""

    if isinstance(obj, (datetime, date)):
        serial = str(obj)
        return serial
    raise TypeError ("Type %s not serializable" % type(obj))


def FixDumps(fn):
    def hook(obj):
        return fn(obj, default=json_serial)

    return hook

def FixDump(fn):
    def hook(obj, fp):
        return fn(obj,fp, default=json_serial)

    return hook


json.dumps=FixDumps(json.dumps)
json.dump=FixDump(json.dump)


if __name__=="__main__":
    today=datetime.now()
    data={'atime':today, 'greet':'Hello'}
    str=json.dumps(data)
    print str

通过导入上述模块,我的其他模块以常规方式(不指定默认关键字)使用json来序列化包含日期时间对象的数据。datetime序列化程序代码会被json.dumps和json.dump自动调用。


0

我最喜欢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)

0

如果您能够安装软件包,我建议您尝试dill,这对于我的项目来说效果很好。这个套件的优点是它具有与相同的介面pickle,因此,如果您已经pickle在专案中使用过,可以简单地以dill为该脚本并查看脚本是否在运行,而无需更改任何代码。因此,这是一个非常便宜的解决方案!

(完全反公开:我与Dill项目毫无关系,也从未参与过该项目。)

安装软件包:

pip install dill

然后,编辑要导入的代码,dill而不是pickle

# import pickle
import dill as pickle

运行您的脚本,看看它是否有效。(如果这样做,您可能需要清理代码,以使您不再隐藏pickle模块名称!)

dill项目页面可以和不能序列化的数据类型的一些细节:

dill 可以腌制以下标准类型:

无,类型,布尔值,整数,长整型,浮点型,复杂,str,unicode,元组,列表,字典,文件,缓冲区,内置,新旧样式类,新旧样式类实例,集合,frozenset,数组,功能,异常

dill 也可以腌制更多“异国”标准类型:

具有yields的函数,嵌套函数,lambdas,单元格,方法,unboundmethod,模块,代码,methodwrapper,dictproxy,methoddescriptor,getsetdescriptor,memberdescriptor,wrapperperscriptor,xrange,slice,未实现,省略号,退出

dill 尚不能腌制这些标准类型:

框架,发生器,回溯



0

要添加另一个选项:您可以使用attrs包和asdict方法。

class ObjectEncoder(JSONEncoder):
    def default(self, o):
        return attr.asdict(o)

json.dumps(objects, cls=ObjectEncoder)

并转换回来

def from_json(o):
    if '_obj_name' in o:
        type_ = o['_obj_name']
        del o['_obj_name']
        return globals()[type_](**o)
    else:
        return o

data = JSONDecoder(object_hook=from_json).decode(data)

类看起来像这样

@attr.s
class Foo(object):
    x = attr.ib()
    _obj_name = attr.ib(init=False, default='Foo')

0

除了Onur的答案外,您可能还想处理类似以下的datetime类型。
(为了处理:“ datetime.datetime”对象没有属性“ dict ”异常。)

def datetime_option(value):
    if isinstance(value, datetime.date):
        return value.timestamp()
    else:
        return value.__dict__

用法:

def toJSON(self):
    return json.dumps(self, default=datetime_option, sort_keys=True, indent=4)

0

首先,我们需要使对象符合JSON,因此可以使用标准JSON模块将其转储。我这样做是这样的:

def serialize(o):
    if isinstance(o, dict):
        return {k:serialize(v) for k,v in o.items()}
    if isinstance(o, list):
        return [serialize(e) for e in o]
    if isinstance(o, bytes):
        return o.decode("utf-8")
    return o

0

基于Quinten Cabo答案

def sterilize(obj):
    if type(obj) in (str, float, int, bool, type(None)):
        return obj
    elif isinstance(obj, dict):
        return {k: sterilize(v) for k, v in obj.items()}
    elif hasattr(obj, '__iter__') and callable(obj.__iter__):
        return [sterilize(v) for v in obj]
    elif hasattr(obj, '__dict__'):
        return {k: sterilize(v) for k, v in obj.__dict__.items() if k not in ['__module__', '__dict__', '__weakref__', '__doc__']}
    else:
        return repr(obj)

区别是

  1. 适用于任何迭代而不是just listtuple(适用于NumPy数组等)
  2. 适用于动态类型(包含 __dict__)。
  3. 包括本机类型floatNone因此它们不会转换为字符串。

留给读者的练习是处理__slots__,这些类既可迭代且具有成员,这些类既是字典又具有成员,等等。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.