Ser*_*gey 730 python serialization json
如何使Python类可序列化?
一个简单的课程:
class FileItem:
def __init__(self, fname):
self.fname = fname
Run Code Online (Sandbox Code Playgroud)
我该怎么做才能得到输出:
>>> import json
>>> my_file = FileItem('/foo/bar')
>>> json.dumps(my_file)
TypeError: Object of type 'FileItem' is not JSON serializable
Run Code Online (Sandbox Code Playgroud)
没有错误(__CODE__)
Onu*_*rım 565
这是一个简单的功能的简单解决方案:
.toJSON() 方法而不是JSON可序列化类,实现序列化方法:
import json
class Object:
def toJSON(self):
return json.dumps(self, default=lambda o: o.__dict__,
sort_keys=True, indent=4)
Run Code Online (Sandbox Code Playgroud)
所以你只需要将其命名为序列化:
me = Object()
me.name = "Onur"
me.age = 35
me.dog = Object()
me.dog.name = "Apollo"
print(me.toJSON())
Run Code Online (Sandbox Code Playgroud)
将输出:
{
"age": 35,
"dog": {
"name": "Apollo"
},
"name": "Onur"
}
Run Code Online (Sandbox Code Playgroud)
Man*_*dan 507
您对预期产量有所了解吗?例如,这会吗?
>>> f = FileItem("/foo/bar")
>>> magic(f)
'{"fname": "/foo/bar"}'
Run Code Online (Sandbox Code Playgroud)
在这种情况下,你只能打电话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"}'
Run Code Online (Sandbox Code Playgroud)
然后将此类json.dumps()作为clskwarg 传递给方法:
json.dumps(cls=MyEncoder)
Run Code Online (Sandbox Code Playgroud)
如果您还想要解码,那么您必须object_hook为该JSONDecoder课程提供自定义.例如
>>> 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>
>>>
Run Code Online (Sandbox Code Playgroud)
gec*_*cco 154
对于更复杂的类,您可以考虑使用jsonpickle工具:
jsonpickle是一个Python库,用于将复杂Python对象与JSON进行序列化和反序列化.
用于将Python编码为JSON的标准Python库,例如stdlib的json,simplejson和demjson,只能处理具有直接JSON等效的Python原语(例如,词典,列表,字符串,整数等).jsonpickle构建在这些库之上,允许将更复杂的数据结构序列化为JSON.jsonpickle具有高度可配置性和可扩展性,允许用户选择JSON后端并添加额外的后端.
Jef*_*kin 78
json模块与你的类一起工作又名,解决:json.dumps({ "thing": YOUR_CLASS() })
toJSONJavaScript)和/或无法使用内置 json 模块注册您的类。当执行类似的操作时json.dumps([1,2, your_obj]),Python 不会检查查找表或对象方法。def __json__(self)将方法添加到您的类中json.dumps以检查__json__方法(影响所有地方,甚至导入 json 的 pip 模块)pip install json-fix
(Fancy John 的答案的扩展+打包版本,谢谢@FancyJohn)
your_class_definition.py
import json_fix
class YOUR_CLASS:
def __json__(self):
# YOUR CUSTOM CODE HERE
# you probably just want to do:
# return self.__dict__
return "a built-in object that is naturally json-able"
Run Code Online (Sandbox Code Playgroud)
就是这样。
用法示例:
from your_class_definition import YOUR_CLASS
import json
json.dumps([1,2, YOUR_CLASS()], indent=0)
# '[\n1,\n2,\n"a built-in object that is naturally json-able"\n]'
Run Code Online (Sandbox Code Playgroud)
要使json.dumpsNumpy 数组、Pandas DataFrame 和其他第 3 方对象正常工作,请参阅模块(只有大约 2 行代码,但需要解释)。
注意:这种方法被简化了,它在已知的边缘情况下失败(例如:如果您的自定义类继承自dict或另一个内置类),并且它错过了控制外部类(numpy 数组、日期时间、数据帧、张量等)的 json 行为。
some_file_thats_imported_before_your_class_definitions.py
from your_class_definition import YOUR_CLASS
import json
json.dumps([1,2, YOUR_CLASS()], indent=0)
# '[\n1,\n2,\n"a built-in object that is naturally json-able"\n]'
Run Code Online (Sandbox Code Playgroud)
your_class_definition.py
# Step: 1
# create the patch
from json import JSONEncoder
def wrapped_default(self, obj):
return getattr(obj.__class__, "__json__", wrapped_default.default)(obj)
wrapped_default.default = JSONEncoder().default
# apply the patch
JSONEncoder.original_default = JSONEncoder.default
JSONEncoder.default = wrapped_default
Run Code Online (Sandbox Code Playgroud)
_
其中,文档中已对此进行了介绍(搜索“complex”以获取编码复数的示例)
and*_*sit 71
大多数答案涉及将调用更改为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
Run Code Online (Sandbox Code Playgroud)
如果您的类只是基本数据表示,那么这种方法很有用,因为您可以始终明确地设置键.
Pau*_*tas 39
另一种选择是将JSON转储包装在自己的类中:
import json
class FileItem:
def __init__(self, fname):
self.fname = fname
def __repr__(self):
return json.dumps(self.__dict__)
Run Code Online (Sandbox Code Playgroud)
或者,更好的是,从类中继承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
Run Code Online (Sandbox Code Playgroud)
测试:
>>> f = FileItem('/foo/bar')
>>> f.toJson()
'{"fname": "/foo/bar"}'
>>> f
'{"fname": "/foo/bar"}'
>>> str(f) # string coercion
'{"fname": "/foo/bar"}'
Run Code Online (Sandbox Code Playgroud)
Jas*_*n S 39
我喜欢Onur的答案,但会扩展为包含一个可选的toJSON()方法来对象自行序列化:
def dumper(obj):
try:
return obj.toJSON()
except:
return obj.__dict__
print json.dumps(some_big_object, default=dumper, indent=2)
Run Code Online (Sandbox Code Playgroud)
use*_*520 33
正如许多其他答案中提到的,您可以传递一个函数来json.dumps将不是默认支持的类型之一的对象转换为支持的类型。令人惊讶的是,他们都没有提到最简单的情况,即使用内置函数vars将对象转换为包含其所有属性的字典:
json.dumps(obj, default=vars)
Run Code Online (Sandbox Code Playgroud)
请注意,这仅涵盖基本情况,如果您需要对某些类型(例如排除某些属性或没有属性的对象)进行更具体的序列化,则需要__dict__使用自定义函数或JSONEncoder其他答案中描述的 a 。
tob*_*gue 24
前几天我遇到了这个问题,并为Python对象实现了一个更通用的版本,可以处理嵌套对象和继承的字段:
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
Run Code Online (Sandbox Code Playgroud)
例:
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)
Run Code Online (Sandbox Code Playgroud)
结果:
{
"a": "A",
"b": [
{
"ab": {
"b": "B",
"i": "I",
"y": "y"
}
}
],
"c": {
"c": "YES"
},
"i": "I"
}
Run Code Online (Sandbox Code Playgroud)
Fan*_*ohn 24
只需to_json在您的类中添加方法,如下所示:
def to_json(self):
return self.message # or how you want it to be serialized
Run Code Online (Sandbox Code Playgroud)
并将此代码(来自此答案)添加到所有内容的顶部:
from json import JSONEncoder
def _default(self, obj):
return getattr(obj.__class__, "to_json", _default.default)(obj)
_default.default = JSONEncoder().default
JSONEncoder.default = _default
Run Code Online (Sandbox Code Playgroud)
这将在导入时修补json模块,因此JSONEncoder.default()会自动检查特殊的"to_json()"方法,并使用它来编码对象(如果找到).
就像Onur说的那样,但这次你不必更新json.dumps()项目中的每一个.
Art*_*yan 17
一个非常简单的单行解决方案
import json
json.dumps(your_object, default=vars)
Run Code Online (Sandbox Code Playgroud)
结束!
下面是一个测试。
import json
from dataclasses import dataclass
@dataclass
class Company:
id: int
name: str
@dataclass
class User:
id: int
name: str
email: str
company: Company
company = Company(id=1, name="Example Ltd")
user = User(id=1, name="John Doe", email="john@doe.net", company=company)
json.dumps(user, default=vars)
Run Code Online (Sandbox Code Playgroud)
输出:
{
"id": 1,
"name": "John Doe",
"email": "john@doe.net",
"company": {
"id": 1,
"name": "Example Ltd"
}
}
Run Code Online (Sandbox Code Playgroud)
R H*_*R H 13
如果您使用的是Python3.5 +,则可以使用jsons。它将把您的对象(及其所有属性递归地)转换成字典。
import jsons
a_dict = jsons.dump(your_object)
Run Code Online (Sandbox Code Playgroud)
或者,如果您想要一个字符串:
a_str = jsons.dumps(your_object)
Run Code Online (Sandbox Code Playgroud)
或者如果您的班级实施了jsons.JsonSerializable:
a_dict = your_object.json
Run Code Online (Sandbox Code Playgroud)
try*_*000 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')))
Run Code Online (Sandbox Code Playgroud)
如果使用标准json,你需要定义一个default函数
import json
def default(o):
return o._asdict()
print(json.dumps(User('alice', 'alice@mail.com'), default=default))
Run Code Online (Sandbox Code Playgroud)
最简单的答案
class Object(dict):
def __init__(self):
pass
def __getattr__(self, key):
return self[key]
def __setattr__(self, key, value):
self[key] = value
# test
obj = Object()
obj.name = "John"
obj.age = 25
obj.brothers = [ Object() ]
text = json.dumps(obj)
Run Code Online (Sandbox Code Playgroud)
现在它为您提供输出,不要对 json.dumps(...) 进行任何更改
'{"name": "John", "age": 25, "brothers": [{}]}'
Run Code Online (Sandbox Code Playgroud)
json在它可以打印的对象方面受到限制,并且jsonpickle(您可能需要a pip install jsonpickle)受到限制,因为它不能缩进文本.如果你想检查一个你不能改变它的类的对象的内容,我仍然找不到比以下更直接的方法:
import json
import jsonpickle
...
print json.dumps(json.loads(jsonpickle.encode(object)), indent=2)
Run Code Online (Sandbox Code Playgroud)
请注意,他们仍然无法打印对象方法.
为了扑灭这场长达 11 年的火灾,我需要一个满足以下标准的解决方案:
json.dumps(obj)json.dumps(obj)json.dumps(如自定义序列化程序)IE:
fileItem = FileItem('filename.ext')
assert json.dumps(fileItem) == '{"fname": "filename.ext"}'
assert fileItem.fname == 'filename.ext'
Run Code Online (Sandbox Code Playgroud)
我的解决方案是:
dictdictclass FileItem(dict):
def __init__(self, fname):
self['fname'] = fname
#fname property
fname: str = property()
@fname.getter
def fname(self):
return self['fname']
@fname.setter
def fname(self, value: str):
self['fname'] = value
#Repeat for other properties
Run Code Online (Sandbox Code Playgroud)
是的,如果您有很多属性,这有点啰嗦,但它是 JSONSerialized 并且它的行为就像一个对象,您可以将它提供给任何需要它的库json.dumps(obj)。
这是我的 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)
Run Code Online (Sandbox Code Playgroud)
这个类可以做到这一点,它将对象转换为标准的json.
import json
class Serializer(object):
@staticmethod
def serialize(object):
return json.dumps(object, default=lambda o: o.__dict__.values()[0])
Run Code Online (Sandbox Code Playgroud)
用法:
Serializer.serialize(my_object)
Run Code Online (Sandbox Code Playgroud)
在python2.7和工作python3.
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__
Run Code Online (Sandbox Code Playgroud)
请注意,我们需要两个步骤来加载。目前,该__python__房产尚未使用。
使用AlJohri的方法,我检查了方法的受欢迎程度:
序列化(Python -> JSON):
to_json: 266,595 于 2018-06-27toJSON:2018-06-27 96,307__json__: 8,504 于 2018-06-27for_json: 6,937 于 2018-06-27反序列化(JSON -> Python):
from_json: 226,101 于 2018-06-27| 归档时间: |
|
| 查看次数: |
606683 次 |
| 最近记录: |