使 Python json 编码器支持 Python 的新数据类
Make the Python json encoder support Python's new dataclasses
从 Python 3.7 开始,有一种叫做数据类的东西:
from dataclasses import dataclass
@dataclass
class Foo:
x: str
但是,以下操作失败:
>>> import json
>>> foo = Foo(x="bar")
>>> json.dumps(foo)
TypeError: Object of type Foo is not JSON serializable
如何使 json.dumps()
将 Foo
的实例编码为 json objects?
就像您可以为 datetime
objects 或 Decimals 添加对 JSON 编码器的支持一样,您还可以提供自定义编码器子类来序列化数据类:
import dataclasses, json
class EnhancedJSONEncoder(json.JSONEncoder):
def default(self, o):
if dataclasses.is_dataclass(o):
return dataclasses.asdict(o)
return super().default(o)
json.dumps(foo, cls=EnhancedJSONEncoder)
不能直接用dataclasses.asdict()
函数转换dataclass吗
听写?类似于:
>>> @dataclass
... class Foo:
... a: int
... b: int
...
>>> x = Foo(1,2)
>>> json.dumps(dataclasses.asdict(x))
'{"a": 1, "b": 2}'
如果您可以为此使用库,则可以使用 dataclasses-json。这是一个例子:
from dataclasses import dataclass
from dataclasses_json import dataclass_json
@dataclass_json
@dataclass
class Foo:
x: str
foo = Foo(x="some-string")
foo_json = foo.to_json()
它还支持嵌入式数据类 - 如果你的数据类有一个字段类型为另一个数据类 - 如果所有涉及的数据类都有 @dataclass_json
装饰器。
获取 JSON 化数据类实例的方法
有几个选项可以实现该目标,每个选项的选择都意味着分析哪种方法最适合您的需求:
Standart library: dataclass.asdict
import dataclasses
import json
@dataclass.dataclass
class Foo:
x: str
foo = Foo(x='1')
json_foo = json.dumps(dataclasses.asdict(foo)) # '{"x": "1"}'
将其恢复为数据类实例并非易事,因此您可能需要访问该答案
Marshmallow Dataclass
from dataclasses import field
from marshmallow_dataclass import dataclass
@dataclass
class Foo:
x: int = field(metadata={"required": True})
foo = Foo(x='1') # Foo(x='1')
json_foo = foo.Schema().dumps(foo) # '{"x": "1"}'
# Back to class instance.
Foo.Schema().loads(json_foo) # Foo(x=1)
作为 marshmallow_dataclass
的奖励,您可以在字段本身上使用验证,当有人使用该模式从 json 反序列化对象时将使用该验证。
Dataclasses Json
from dataclasses import dataclass
from dataclasses_json import dataclass_json
@dataclass_json
@dataclass
class Foo:
x: int
foo = Foo(x='1')
json_foo = foo.to_json() # Foo(x='1')
# Back to class instance
Foo.from_json(json_foo) # Foo(x='1')
此外,除了棉花糖数据类为您进行类型转换的通知之外,而 dataclassses-json(ver.: 0.5.1) 忽略了这一点。
遵循已接受的 miracle2k 答案并重复使用自定义 json 编码器。
使用字典解包
可以找到更简单的答案on Reddit
>>> from dataclasses import dataclass
>>> @dataclass
... class MyData:
... prop1: int
... prop2: str
... prop3: int
...
>>> d = {'prop1': 5, 'prop2': 'hi', 'prop3': 100}
>>> my_data = MyData(**d)
>>> my_data
MyData(prop1=5, prop2='hi', prop3=100)
我建议使用 to_json()
方法为您的数据class创建父级 class:
import json
from dataclasses import dataclass, asdict
@dataclass
class Dataclass:
def to_json(self) -> str:
return json.dumps(asdict(self))
@dataclass
class YourDataclass(Dataclass):
a: int
b: int
x = YourDataclass(a=1, b=2)
x.to_json() # '{"a": 1, "b": 2}'
如果您要向所有数据添加其他功能,这将特别有用classes。
好的,这就是我在类似情况下所做的。
创建将嵌套数据 类 转换为字典的自定义字典工厂。
def myfactory(数据):
return dict(x for x in data if x[1] is not None)
如果 foo 是您的@dataclass,那么只需提供您的字典工厂以使用“myfactory()”方法:
fooDict = asdict(foo, dict_factory=myfactory)
将 fooDict 转换为 json
fooJson = json.dumps(fooDict)
这应该行得通!!
dataclass-wizard 是适合您的现代选项。它支持日期和时间等复杂类型,typing
模块中的大多数泛型,以及 嵌套数据类 结构。
PEP 585 and 604 中引入的“新样式”注释可以通过 __future__
导入移植回 Python 3.7,如下所示。
from __future__ import annotations # This can be removed in Python 3.10
from dataclasses import dataclass, field
from dataclass_wizard import JSONWizard
@dataclass
class MyClass(JSONWizard):
my_str: str | None
is_active_tuple: tuple[bool, ...]
list_of_int: list[int] = field(default_factory=list)
string = """
{
"my_str": 20,
"ListOfInt": ["1", "2", 3],
"isActiveTuple": ["true", false, 1]
}
"""
instance = MyClass.from_json(string)
print(repr(instance))
# MyClass(my_str='20', is_active_tuple=(True, False, True), list_of_int=[1, 2, 3])
print(instance.to_json())
# '{"myStr": "20", "isActiveTuple": [true, false, true], "listOfInt": [1, 2, 3]}'
# True
assert instance == MyClass.from_json(instance.to_json())
您可以使用 pip
安装数据类向导:
$ pip install dataclass-wizard
一些背景信息:
For serialization, it uses a slightly modified (a bit more efficient) implementation of dataclasses.asdict
. When de-serializing JSON to a dataclass instance, the first time it iterates over the dataclass fields and generates a parser for each annotated type, which makes it more efficient when the de-serialization process is run multiple times.
免责声明:我是这个库的创建者(和维护者)。
对 dataclass
和 SimpleNamespace
对象进行编码的最简单方法是为 json.dumps()
提供默认函数,该函数为无法以其他方式序列化的对象调用,并且 return 对象 __dict__
:
json.dumps(foo, default=lambda o: o.__dict__)
您还可以在 class 中实现 asdict
和 json.dumps
方法。在这种情况下,没有必要将 json.dumps
导入项目的其他部分:
from typing import List
from dataclasses import dataclass, asdict, field
from json import dumps
@dataclass
class TestDataClass:
"""
Data Class for TestDataClass
"""
id: int
name: str
tested: bool = False
test_list: List[str] = field(default_factory=list)
@property
def __dict__(self):
"""
get a python dictionary
"""
return asdict(self)
@property
def json(self):
"""
get the json formated string
"""
return dumps(self.__dict__)
test_object_1 = TestDataClass(id=1, name="Hi")
print(test_object_1.__dict__)
print(test_object_1.json)
输出:
{'id': 1, 'name': 'Hi', 'tested': False, 'test_list': []}
{"id": 1, "name": "Hi", "tested": false, "test_list": []}
您还可以创建一个父级 class 来继承这些方法:
from typing import List
from dataclasses import dataclass, asdict, field
from json import dumps
@dataclass
class SuperTestDataClass:
@property
def __dict__(self):
"""
get a python dictionary
"""
return asdict(self)
@property
def json(self):
"""
get the json formated string
"""
return dumps(self.__dict__)
@dataclass
class TestDataClass(SuperTestDataClass):
"""
Data Class for TestDataClass
"""
id: int
name: str
tested: bool = False
test_list: List[str] = field(default_factory=list)
test_object_1 = TestDataClass(id=1, name="Hi")
print(test_object_1.__dict__)
print(test_object_1.json)
从 Python 3.7 开始,有一种叫做数据类的东西:
from dataclasses import dataclass
@dataclass
class Foo:
x: str
但是,以下操作失败:
>>> import json
>>> foo = Foo(x="bar")
>>> json.dumps(foo)
TypeError: Object of type Foo is not JSON serializable
如何使 json.dumps()
将 Foo
的实例编码为 json objects?
就像您可以为 datetime
objects 或 Decimals 添加对 JSON 编码器的支持一样,您还可以提供自定义编码器子类来序列化数据类:
import dataclasses, json
class EnhancedJSONEncoder(json.JSONEncoder):
def default(self, o):
if dataclasses.is_dataclass(o):
return dataclasses.asdict(o)
return super().default(o)
json.dumps(foo, cls=EnhancedJSONEncoder)
不能直接用dataclasses.asdict()
函数转换dataclass吗
听写?类似于:
>>> @dataclass
... class Foo:
... a: int
... b: int
...
>>> x = Foo(1,2)
>>> json.dumps(dataclasses.asdict(x))
'{"a": 1, "b": 2}'
如果您可以为此使用库,则可以使用 dataclasses-json。这是一个例子:
from dataclasses import dataclass
from dataclasses_json import dataclass_json
@dataclass_json
@dataclass
class Foo:
x: str
foo = Foo(x="some-string")
foo_json = foo.to_json()
它还支持嵌入式数据类 - 如果你的数据类有一个字段类型为另一个数据类 - 如果所有涉及的数据类都有 @dataclass_json
装饰器。
获取 JSON 化数据类实例的方法
有几个选项可以实现该目标,每个选项的选择都意味着分析哪种方法最适合您的需求:
Standart library: dataclass.asdict
import dataclasses
import json
@dataclass.dataclass
class Foo:
x: str
foo = Foo(x='1')
json_foo = json.dumps(dataclasses.asdict(foo)) # '{"x": "1"}'
将其恢复为数据类实例并非易事,因此您可能需要访问该答案
Marshmallow Dataclass
from dataclasses import field
from marshmallow_dataclass import dataclass
@dataclass
class Foo:
x: int = field(metadata={"required": True})
foo = Foo(x='1') # Foo(x='1')
json_foo = foo.Schema().dumps(foo) # '{"x": "1"}'
# Back to class instance.
Foo.Schema().loads(json_foo) # Foo(x=1)
作为 marshmallow_dataclass
的奖励,您可以在字段本身上使用验证,当有人使用该模式从 json 反序列化对象时将使用该验证。
Dataclasses Json
from dataclasses import dataclass
from dataclasses_json import dataclass_json
@dataclass_json
@dataclass
class Foo:
x: int
foo = Foo(x='1')
json_foo = foo.to_json() # Foo(x='1')
# Back to class instance
Foo.from_json(json_foo) # Foo(x='1')
此外,除了棉花糖数据类为您进行类型转换的通知之外,而 dataclassses-json(ver.: 0.5.1) 忽略了这一点。
遵循已接受的 miracle2k 答案并重复使用自定义 json 编码器。
使用字典解包
可以找到更简单的答案on Reddit>>> from dataclasses import dataclass
>>> @dataclass
... class MyData:
... prop1: int
... prop2: str
... prop3: int
...
>>> d = {'prop1': 5, 'prop2': 'hi', 'prop3': 100}
>>> my_data = MyData(**d)
>>> my_data
MyData(prop1=5, prop2='hi', prop3=100)
我建议使用 to_json()
方法为您的数据class创建父级 class:
import json
from dataclasses import dataclass, asdict
@dataclass
class Dataclass:
def to_json(self) -> str:
return json.dumps(asdict(self))
@dataclass
class YourDataclass(Dataclass):
a: int
b: int
x = YourDataclass(a=1, b=2)
x.to_json() # '{"a": 1, "b": 2}'
如果您要向所有数据添加其他功能,这将特别有用classes。
好的,这就是我在类似情况下所做的。
创建将嵌套数据 类 转换为字典的自定义字典工厂。
def myfactory(数据): return dict(x for x in data if x[1] is not None)
如果 foo 是您的@dataclass,那么只需提供您的字典工厂以使用“myfactory()”方法:
fooDict = asdict(foo, dict_factory=myfactory)
将 fooDict 转换为 json
fooJson = json.dumps(fooDict)
这应该行得通!!
dataclass-wizard 是适合您的现代选项。它支持日期和时间等复杂类型,typing
模块中的大多数泛型,以及 嵌套数据类 结构。
PEP 585 and 604 中引入的“新样式”注释可以通过 __future__
导入移植回 Python 3.7,如下所示。
from __future__ import annotations # This can be removed in Python 3.10
from dataclasses import dataclass, field
from dataclass_wizard import JSONWizard
@dataclass
class MyClass(JSONWizard):
my_str: str | None
is_active_tuple: tuple[bool, ...]
list_of_int: list[int] = field(default_factory=list)
string = """
{
"my_str": 20,
"ListOfInt": ["1", "2", 3],
"isActiveTuple": ["true", false, 1]
}
"""
instance = MyClass.from_json(string)
print(repr(instance))
# MyClass(my_str='20', is_active_tuple=(True, False, True), list_of_int=[1, 2, 3])
print(instance.to_json())
# '{"myStr": "20", "isActiveTuple": [true, false, true], "listOfInt": [1, 2, 3]}'
# True
assert instance == MyClass.from_json(instance.to_json())
您可以使用 pip
安装数据类向导:
$ pip install dataclass-wizard
一些背景信息:
For serialization, it uses a slightly modified (a bit more efficient) implementation of
dataclasses.asdict
. When de-serializing JSON to a dataclass instance, the first time it iterates over the dataclass fields and generates a parser for each annotated type, which makes it more efficient when the de-serialization process is run multiple times.
免责声明:我是这个库的创建者(和维护者)。
对 dataclass
和 SimpleNamespace
对象进行编码的最简单方法是为 json.dumps()
提供默认函数,该函数为无法以其他方式序列化的对象调用,并且 return 对象 __dict__
:
json.dumps(foo, default=lambda o: o.__dict__)
您还可以在 class 中实现 asdict
和 json.dumps
方法。在这种情况下,没有必要将 json.dumps
导入项目的其他部分:
from typing import List
from dataclasses import dataclass, asdict, field
from json import dumps
@dataclass
class TestDataClass:
"""
Data Class for TestDataClass
"""
id: int
name: str
tested: bool = False
test_list: List[str] = field(default_factory=list)
@property
def __dict__(self):
"""
get a python dictionary
"""
return asdict(self)
@property
def json(self):
"""
get the json formated string
"""
return dumps(self.__dict__)
test_object_1 = TestDataClass(id=1, name="Hi")
print(test_object_1.__dict__)
print(test_object_1.json)
输出:
{'id': 1, 'name': 'Hi', 'tested': False, 'test_list': []}
{"id": 1, "name": "Hi", "tested": false, "test_list": []}
您还可以创建一个父级 class 来继承这些方法:
from typing import List
from dataclasses import dataclass, asdict, field
from json import dumps
@dataclass
class SuperTestDataClass:
@property
def __dict__(self):
"""
get a python dictionary
"""
return asdict(self)
@property
def json(self):
"""
get the json formated string
"""
return dumps(self.__dict__)
@dataclass
class TestDataClass(SuperTestDataClass):
"""
Data Class for TestDataClass
"""
id: int
name: str
tested: bool = False
test_list: List[str] = field(default_factory=list)
test_object_1 = TestDataClass(id=1, name="Hi")
print(test_object_1.__dict__)
print(test_object_1.json)