GVKun编程网logo

Python-使用常规编码器使对象JSON可序列化(python编码器用什么)

18

对于Python-使用常规编码器使对象JSON可序列化感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍python编码器用什么,并为您提供关于'类型集不是可序列化的JSON',但数据是字典-py

对于Python-使用常规编码器使对象JSON可序列化感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍python编码器用什么,并为您提供关于'类型集不是可序列化的JSON',但数据是字典-python、ansible – 内联加密变量,不是JSON可序列化的、AppEngine使NDB模型JSON可序列化、JSON序列化比Python中的yaml序列化快得多吗?的有用信息。

本文目录一览:

Python-使用常规编码器使对象JSON可序列化(python编码器用什么)

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

如何解决''类型集不是可序列化的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可序列化的

ansible – 内联加密变量,不是JSON可序列化的

我试图了解如何使用保险库加密单个变量.首先,我使用ansible-vault encrypt_string -n -p加密字符串,然后将输出写入我的playbook.当我执行playbook时,它说解密的字符串不是 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可序列化

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序列化快得多吗?

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序列化快得多吗?的相关信息,请在本站查询。

本文标签: