Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何使类JSON可序列化_Python_Json_Serialization - Fatal编程技术网

Python 如何使类JSON可序列化

Python 如何使类JSON可序列化,python,json,serialization,Python,Json,Serialization,如何使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 'FileIt

如何使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

没有错误

您对预期输出有什么想法?例如,这样做行吗

>>> f  = FileItem("/foo/bar")
>>> magic(f)
'{"fname": "/foo/bar"}'
在这种情况下,您只能调用
json.dumps(f.\uu dict\uu)

如果您想要更多定制的输出,那么您必须子类化并实现自己的定制序列化

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

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

>>> MyEncoder().encode(f)
'{"fname": "/foo/bar"}'
然后将该类作为
cls
kwarg传递到方法中:

json.dumps(cls=MyEncoder)
如果您还想解码,那么您必须向类提供一个自定义的
对象\u hook
。例如:

>>> 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>
>>> 
>>def from_json(json_对象):
如果json_对象中的“fname”:
返回FileItem(json_对象['fname'])
>>>f=JSONDecoder(object\u hook=from\u json).decode(“{”fname:“/foo/bar”}”)
>>>f
>>> 

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

jsonpickle是一个Python库,用于在JSON之间对复杂Python对象进行序列化和反序列化

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


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

import json

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

    def __repr__(self):
        return json.dumps(self.__dict__)
或者,更好的是,从
JsonSerializable
类中对FileItem类进行子类化:

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

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

.toJSON()
方法 实现序列化程序方法,而不是JSON可序列化类:

导入json
类对象:
def toJSON(self):
返回json.dumps(self,default=lambda o:o.。\uuuuu dict\uuuuu,
排序(关键字=True,缩进=4)
所以您只需调用它来序列化:

me=Object()
me.name=“Onur”
年龄=35
me.dog=Object()
me.dog.name=“阿波罗”
打印(me.toJSON())
将输出:

{
“年龄”:35岁,
“狗”:{
“名称”:“阿波罗”
},
“名称”:“Onur”
}

这是我的3美分…
这演示了类似于树的python对象的显式json序列化。
注意:如果你真的想要一些这样的代码,你可以使用这个类


jsonweb似乎是我最好的解决方案。看

我喜欢但会扩展到包含一个可选的
toJSON()
方法,用于对象序列化自身:

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

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

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
如果使用标准的
json
,则需要定义一个
default
函数

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

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

大多数答案都涉及将调用更改为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

如果您的类只是基本的数据表示,那么这一点就行了,对于更复杂的事情,您总是可以显式地设置键。

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

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
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)
导入json
进口检验
类ObjectEncoder(json.JSONEncoder):
def默认值(自身、obj):
如果hasattr(obj,“to_json”):
返回self.default(obj.to_json())
埃利夫·哈斯塔特(obj),“口述”:
d=听写(
(关键、价值)
对于键,inspect.getmembers(obj)中的值
如果不是键,则用(“\uuuuuuu”)启动
而不是检查。isabstract(值)
和不检查。isbuiltin(值)
和不检查。isfunction(值)
和不检查。isgenerator(值)
和不检查。isgeneratorfunction(值)
和不检查。ismethod(值)
和不检查。ismethoddescriptor(值)
和不检查。isroutine(值)
)
返回self.default(d)
返回obj
例如:

C类(对象):
c=“否”
def to_json(self):
返回{“c”:“是”}
B类(对象):
b=“b”
i=“i”
定义初始化(self,y):
self.y=y
def f(自我):
打印“f”
A类(B类):
a=“a”
定义初始化(自):
self.b=[{“ab”:b(“y”)}]
self.c=c()
打印json.dumps(A(),cls=ObjectEncoder,indent=2,sort\u keys=True)
结果:

{
“a”:“a”,
“b”:[
{
“ab”:{
“b”:“b”,
“我”:“我”,
“y”:“y”
}
}
], 
“c”:{
“c”:“是”
}, 
“我”:“我”
}

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

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

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

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

def to_json(self):
  return self.message # or how you want it to be serialized
class SomeClass(Model):
    json_field = JSONField()
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)
并将此代码(从)添加到所有内容的顶部:

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模块时对其进行修补 default()自动检查特殊的“to_json() 方法,并使用它对找到的对象进行编码


正如Onur所说,但这次您不必更新项目中的每个
json.dumps()

这个类可以做到这一点,它将对象转换为标准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)
pytho中工作
pip install json-tricks
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
                }
        }
}
from json_tricks import loads
json_str = loads(json_str)
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
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)
# 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__
class SomeClass(Model):
    json_field = JSONField()
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)
class SomeClass(Model):
    json_field = JSONField(dumps=CustomJsonEncoder.json_dumper)
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_model = WhateverPeeweeModel()
new_model = SomeClass()
new_model.json_field = model_to_dict(peewee_model)
pip install dill
# import pickle
import dill as pickle
import jsons

a_dict = jsons.dump(your_object)
a_str = jsons.dumps(your_object)
a_dict = your_object.json
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))
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')
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
def sterilize(obj):
    """Make an object more ameniable to dumping as json
    """
    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()}
    list_ret = []
    dict_ret = {}
    for a in dir(obj):
        if a == '__iter__' and callable(obj.__iter__):
            list_ret.extend([sterilize(v) for v in obj])
        elif a == '__dict__':
            dict_ret.update({k: sterilize(v) for k, v in obj.__dict__.items() if k not in ['__module__', '__dict__', '__weakref__', '__doc__']})
        elif a not in ['__doc__', '__module__']:
            aval = getattr(obj, a)
            if type(aval) in (str, float, int, bool, type(None)):
                dict_ret[a] = aval
            elif a != '__class__' and a != '__objclass__' and isinstance(aval, type):
                dict_ret[a] = sterilize(aval)
    if len(list_ret) == 0:
        if len(dict_ret) == 0:
            return repr(obj)
        return dict_ret
    else:
        if len(dict_ret) == 0:
            return list_ret
    return (list_ret, dict_ret)
class DObject(json.JSONEncoder):
    def delete_not_related_keys(self, _dict):
        for key in ["skipkeys", "ensure_ascii", "check_circular", "allow_nan", "sort_keys", "indent"]:
            try:
                del _dict[key]
            except:
                continue

    def default(self, o):
        if hasattr(o, '__dict__'):
            my_dict = o.__dict__.copy()
            self.delete_not_related_keys(my_dict)
            return my_dict
        else:
            return o

a = DObject()
a.name = 'abdul wahid'
b = DObject()
b.name = a

print(json.dumps(b, cls=DObject))
 instance.toJSON()
 instance.asJSON()
{
    "members": {
        "Flintstone,Fred": {
            "firstName": "Fred",
            "lastName": "Flintstone"
        },
        "Flintstone,Wilma": {
            "firstName": "Wilma",
            "lastName": "Flintstone"
        }
    },
    "name": "The Flintstones"
}
{'name': 'The Flintstones', 'members': {'Flintstone,Fred': {'firstName': 'Fred', 'lastName': 'Flintstone'}, 'Flintstone,Wilma': {'firstName': 'Wilma', 'lastName': 'Flintstone'}}}
def testJsonAble(self):
        family=Family("The Flintstones")
        family.add(Person("Fred","Flintstone")) 
        family.add(Person("Wilma","Flintstone"))
        json1=family.toJSON()
        json2=family.asJSON()
        print(json1)
        print(json2)

class Family(JSONAble):
    def __init__(self,name):
        self.name=name
        self.members={}
    
    def add(self,person):
        self.members[person.lastName+","+person.firstName]=person

class Person(JSONAble):
    def __init__(self,firstName,lastName):
        self.firstName=firstName;
        self.lastName=lastName;
 '''
Created on 2020-09-03

@author: wf
'''
import json

class JSONAble(object):
    '''
    mixin to allow classes to be JSON serializable see
    https://stackoverflow.com/questions/3768895/how-to-make-a-class-json-serializable
    '''

    def __init__(self):
        '''
        Constructor
        '''
    
    def toJSON(self):
        return json.dumps(self, default=lambda o: o.__dict__, 
            sort_keys=True, indent=4)
        
    def getValue(self,v):
        if (hasattr(v, "asJSON")):
            return v.asJSON()
        elif type(v) is dict:
            return self.reprDict(v)
        elif type(v) is list:
            vlist=[]
            for vitem in v:
                vlist.append(self.getValue(vitem))
            return vlist
        else:   
            return v
    
    def reprDict(self,srcDict):
        '''
        get my dict elements
        '''
        d = dict()
        for a, v in srcDict.items():
            d[a]=self.getValue(v)
        return d
    
    def asJSON(self):
        '''
        recursively return my dict elements
        '''
        return self.reprDict(self.__dict__)   
json.dumps(obj, default=vars)