对于Python-使用常规编码器使对象JSON可序列化感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍python编码器用什么,并为您提供关于'类型集不是可序列化的JSON',但数据是字典-py
对于Python-使用常规编码器使对象JSON可序列化感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍python编码器用什么,并为您提供关于'类型集不是可序列化的JSON',但数据是字典-python、ansible – 内联加密变量,不是JSON可序列化的、AppEngine使NDB模型JSON可序列化、JSON序列化比Python中的yaml序列化快得多吗?的有用信息。
本文目录一览:- Python-使用常规编码器使对象JSON可序列化(python编码器用什么)
- '类型集不是可序列化的JSON',但数据是字典-python
- ansible – 内联加密变量,不是JSON可序列化的
- AppEngine使NDB模型JSON可序列化
- JSON序列化比Python中的yaml序列化快得多吗?
Python-使用常规编码器使对象JSON可序列化(python编码器用什么)
JSON序列化自定义非序列化对象的常规方法是子类化json.JSONEncoder
,然后将自定义编码器传递给转储。
通常看起来像这样:
class CustomEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, foo): return obj.to_json() return json.JSONEncoder.default(self, obj)print json.dumps(obj, cls = CustomEncoder)
我想做的是使默认编码器可序列化的东西。我环顾四周,但找不到任何东西。我的想法是,编码器将在某些字段中确定json编码。类似的东西__str__
。也许是一个__json__
领域。python中是否有类似的东西?
我想使我要制作的模块的一个类可以对使用该包的每个人进行JSON序列化,而无需他们担心实现自己的[琐碎]自定义编码器。
答案1
小编典典正如我在对你的问题的评论中所说的那样,在查看了json模块的源代码之后,它似乎没有根据自己的意愿来做。但是,可以通过所谓的猴子修补来实现该目标 (请参阅问题什么是猴子修补?)。这可以在你程序包的__init__.py
初始化脚本中完成,并且会影响所有后续的json模块序列化,因为模块通常只加载一次,结果缓存在中sys.modules
。
该补丁会更改默认的json编码器的default
方法,即default default()
。
为了简单起见,以下示例实现为独立模块:
模组: make_json_serializable.py
""" Module that monkey-patches json module when it''s imported soJSONEncoder.default() automatically checks for a special "to_json()"method and uses it to encode the object if found."""from json import JSONEncoderdef _default(self, obj): return getattr(obj.__class__, "to_json", _default.default)(obj)_default.default = JSONEncoder.default # Save unmodified default.JSONEncoder.default = _default # Replace it.
使用补丁很简单,因为只需导入模块即可应用补丁。
客户端脚本示例:
import jsonimport make_json_serializable # apply monkey-patchclass Foo(object): def __init__(self, name): self.name = name def to_json(self): # New special method. """ Convert to JSON format string representation. """ return ''{"name": "%s"}'' % self.namefoo = Foo(''sazpaz'')print(json.dumps(foo)) # -> "{\"name\": \"sazpaz\"}"
为了保留对象类型信息,特殊方法还可以将其包含在返回的字符串中:
return (''{"type": "%s", "name": "%s"}'' % (self.__class__.__name__, self.name))
它将产生以下现在包含类名称的JSON:
"{\"type\": \"Foo\", \"name\": \"sazpaz\"}"
魔术师躺在这里
与让替换项default()
寻找一个特殊命名的方法相比,甚至更好的是,它能够自动序列化大多数Python对象,包括用户定义的类实例,而无需添加特殊方法。在研究了许多备选方案之后,以下使用该pickle模块的方案对我而言似乎最接近于该理想方案:
模组: make_json_serializable2.py
""" Module that imports the json module and monkey-patches it soJSONEncoder.default() automatically pickles any Python objectsencountered that aren''t standard JSON data types."""from json import JSONEncoderimport pickledef _default(self, obj): return {''_python_object'': pickle.dumps(obj)}JSONEncoder.default = _default # Replace with the above.
当然,不能对所有内容进行腌制-例如扩展名。但是,有一些方法定义了通过pickle协议通过编写特殊方法来处理它们的方法(类似于你之前和我所描述的方法),但是这样做的情况可能要少得多。
反序列化
无论如何,使用pickle
协议还意味着通过在传入的字典中使用任何键的object_hook
任何json.loads()
调用上提供自定义函数参数''_python_object''
(只要有一个键),就很容易重建原始的Python对象。就像是:
def as_python_object(dct): try: return pickle.loads(str(dct[''_python_object''])) except KeyError: return dctpyobj = json.loads(json_str, object_hook=as_python_object)
如果必须在许多地方执行此操作,则可能有必要定义一个自动提供额外关键字参数的包装函数:
json_pkloads = functools.partial(json.loads, object_hook=as_python_object)pyobj = json_pkloads(json_str)
当然,也可以通过猴子将其修补到json模块中,从而使函数成为默认值object_hook
(而不是None)。
我的想法用pickle从答案由雷蒙德赫廷杰另一个JSON序列化的问题,就是我认为非常可靠以及官方源(如在Python核心开发人员)。
可移植到Python 3
上面的代码无法像Python 3所示那样工作,因为它json.dumps()
返回了一个无法处理的bytes对象JSONEncoder。但是,该方法仍然有效。一个简单的方法来解决该问题是latin1“解码”,从返回的值pickle.dumps()
,然后选择“编码”它latin1
传递到之前pickle.loads(
)的as_python_object()
功能。这工作,因为任意的二进制字符串是有效的latin1
,可总是被解码为Unicode,然后再编码回原来的字符串(如指出,这个答案由斯文Marnach)。
(尽管以下内容在Python 2中可以正常工作,但latin1
它的解码和编码是多余的。)
from decimal import Decimalclass PythonObjectEncoder(json.JSONEncoder): def default(self, obj): return {''_python_object'': pickle.dumps(obj).decode(''latin1'')}def as_python_object(dct): try: return pickle.loads(dct[''_python_object''].encode(''latin1'')) except KeyError: return dctclass Foo(object): # Some user-defined class. def __init__(self, name): self.name = name def __eq__(self, other): if not isinstance(other, type(self)): # Don''t attempt to compare against unrelated types. return NotImplemented return self.name == other.namedata = [1,2,3, set([''knights'', ''who'', ''say'', ''ni'']), {''key'':''value''}, Foo(''Bar''), Decimal(''3.141592653589793238462643383279502884197169'')]j = json.dumps(data, cls=PythonObjectEncoder, indent=4)data2 = json.loads(j, object_hook=as_python_object)assert data == data2 # both should be same
'类型集不是可序列化的JSON',但数据是字典-python
如何解决''类型集不是可序列化的JSON'',但数据是字典-python?
我正在使用Microsoft的graph API发送电子邮件,因此我可以动态调整电子邮件的内容,我将电子邮件的有效负载设置为使用msg变量,该变量将根据某些输入进行调整。为了便于阅读,我将其设置为dict:
payload = {
"message": {
"subject": "Some Subject","body": {
"contentType": "Text","content": msg
},"toRecipients": [
{
"emailAddress": {
"somememail@email.com"
}
}
]
},"savetoSentItemn": "false"
}
然后我要使用json.dumps(payload)将其转换为API的必要格式。但是,json.dumps会引发错误:
TypeError: Object of type set is not JSON serializable
我不知道这是一组。当一切设置如下时,我不应该通过API发送电子邮件:
payload = "{\n \"message\": {\n \"subject\": \"Some Subject\",\n \"body\": {\n \"contentType\": \"Text\",\n \"content\": \"Some content.\"\n },\n \"toRecipients\": [\n {\n \"emailAddress\": {\n \"address\": \"someemail@email.com\"\n }\n }\n ]\n },\n \"savetoSentItems\": \"false\"\n}"
但是阅读起来很糟糕。有人看到我的错误导致了错误吗? 谢谢
解决方法
在Python中,大括号可用于初始化集合(docs)。
在您的有效载荷中,emailAddress
的值包装在{}
中:
{
"emailAddress": {
"somememail@email.com"
}
}
注意:
>>> x = {"somememail@email.com"}
>>> type(x)
<class ''set''>
在大括号内添加一个键会将您的设置变成字典:
{
"emailAddress": {
"address": "somememail@email.com"
}
}
ansible – 内联加密变量,不是JSON可序列化的
加密字符串:“inline_name”
我也尝试使用inline_name和inlinename,每次都有相同的结果.
我的剧本:
--- - name: Build System hosts: dev tasks: - name: Create MysqL_db: state: present name: !vault | $ANSIBLE_VAULT;1.1;AES256 39613261386438623937643062636166663638633062323939343734306334346537613233623064 3761633832326365356231633338396132646532313861350a316666376566616633376238313636 39343833306462323534623238333639663734626662623731666239366566643636386261643164 3861363730336331660a316165633232323732633364346636363764623639356562336536636136 6364 login_host: "{{ MysqL_host }}" login_user: "{{ MysqL_user }}" login_password: "{{ MysqL_pass }}" - name: Check if can access plain text vars debug: msg: "{{ my_plain_txt }}"
错误信息:
An exception occurred during task execution. To see the full traceback,use -vvv. The error was: TypeError: u'"inline_name"' is not JSON serializable fatal: [127.0.0.1]: Failed! => {"Failed": true,"msg": "Unexpected failure during module execution.","stdout": ""}
解决方法
- name: Create MysqL_db: state: present name: "{{ MysqL_name }}" login_host: "{{ MysqL_host }}" login_user: "{{ MysqL_user }}" login_password: "{{ MysqL_pass }}" vars: MysqL_name: !vault | $ANSIBLE_VAULT;1.1;AES256 39613261386438623937643062636166663638633062323939343734306334346537613233623064 3761633832326365356231633338396132646532313861350a316666376566616633376238313636 39343833306462323534623238333639663734626662623731666239366566643636386261643164 3861363730336331660a316165633232323732633364346636363764623639356562336536636136 6364
AppEngine使NDB模型JSON可序列化
我们有一个ndb模型,我们想使json可序列化。这些模型非常简单,遵循以下原则:
class Pasta(ndb.Model): name = ndb.StringProperty() type = ndb.StringProperty() comments = ndb.JsonProperty()
然后,在处理程序方面,我们希望按照以下方式进行操作:
json.dumps(Pasta.query(Pasta.name=="Ravioli").fetch())
并将其返回给客户端,但由于类Pasta不可JSON序列化,因此它始终抛出json解析错误。因此,问题是,我们是否必须实施__str__
,__repr__
或者是否有更灵活的方法?
答案1
小编典典ndb.Model
实例具有以下to_dict()
功能:https
:
//developers.google.com/appengine/docs/python/ndb/modelclass#Model_to_dict
最简单的方法是:
json.dumps([p.to_dict() for p in Pasta.query(Pasta.name == "Ravioli").fetch()])
JSON序列化比Python中的yaml序列化快得多吗?
我的代码在很大程度上依赖yaml进行跨语言序列化,并且在加速某些工作时,我注意到yaml与其他序列化方法(例如pickle,json)相比非常慢。
所以真正令我震惊的是,当输出几乎相同时,json的速度要比Yaml快得多。
>>> import yaml, cjson; d={''foo'': {''bar'': 1}}>>> yaml.dump(d, Dumper=yaml.SafeDumper)''foo: {bar: 1}\n''>>> cjson.encode(d)''{"foo": {"bar": 1}}''>>> import yaml, cjson;>>> timeit("yaml.dump(d, Dumper=yaml.SafeDumper)", setup="import yaml; d={''foo'': {''bar'': 1}}", number=10000)44.506911039352417>>> timeit("yaml.dump(d, Dumper=yaml.CSafeDumper)", setup="import yaml; d={''foo'': {''bar'': 1}}", number=10000)16.852826118469238>>> timeit("cjson.encode(d)", setup="import cjson; d={''foo'': {''bar'': 1}}", number=10000)0.073784112930297852
PyYaml的CSafeDumper和cjson都是用C编写的,因此这并不是C与Python的速度问题。我什至还添加了一些随机数据,以查看cjson是否正在执行任何缓存,但是它仍然比PyYaml快得多。我意识到yaml是json的超集,但是使用这样简单的输入,yaml序列化器怎么会慢2个数量级呢?
答案1
小编典典通常,决定解析速度的不是输出的复杂性,而是接受的输入的复杂性。JSON语法非常简洁。YAML解析器相对复杂,导致开销增加。
JSON的首要设计目标是简单性和通用性。因此,JSON的生成和解析非常简单,但代价是人类可读性降低。它还使用最低公分母信息模型,以确保每个现代编程环境都可以轻松处理任何JSON数据。
相反,YAML的首要设计目标是人类可读性并支持序列化任意本机数据结构。因此,YAML允许可读性极强的文件,但生成和解析更加复杂。此外,YAML的业务范围超出了最低公分母数据类型,因此在不同的编程环境之间进行转换时,需要进行更复杂的处理。
我不是YAML解析器实现者,因此如果没有一些性能分析数据和大量示例集,我就无法具体说明数量级。无论如何,在对基准数字充满信心之前,请务必对大量输入进行测试。
更新“
糟糕”,误解了问题。:-(尽管输入语法很大,但是序列化仍然可以非常快;但是,浏览源代码,看起来PyYAML的Python级序列化构造了一个表示图,而simplejson将内置的Python数据类型直接编码为文本块。
我们今天的关于Python-使用常规编码器使对象JSON可序列化和python编码器用什么的分享已经告一段落,感谢您的关注,如果您想了解更多关于'类型集不是可序列化的JSON',但数据是字典-python、ansible – 内联加密变量,不是JSON可序列化的、AppEngine使NDB模型JSON可序列化、JSON序列化比Python中的yaml序列化快得多吗?的相关信息,请在本站查询。
本文标签: