如何更改可序列化 python 对象的 json 编码行为?

2024-01-05

更改不可 JSON 序列化的对象的格式很容易,例如 datetime.datetime。

出于调试目的,我的要求是改变一些自定义对象从基本对象扩展的方式,例如dict and list,以json格式序列化。代码 :

import datetime
import json

def json_debug_handler(obj):
    print("object received:")
    print type(obj)
    print("\n\n")
    if  isinstance(obj, datetime.datetime):
        return obj.isoformat()
    elif isinstance(obj,mDict):
        return {'orig':obj , 'attrs': vars(obj)}
    elif isinstance(obj,mList):
        return {'orig':obj, 'attrs': vars(obj)}
    else:
        return None


class mDict(dict):
    pass


class mList(list):
    pass


def test_debug_json():
    games = mList(['mario','contra','tetris'])
    games.src = 'console'
    scores = mDict({'dp':10,'pk':45})
    scores.processed = "unprocessed"
    test_json = { 'games' : games , 'scores' : scores , 'date': datetime.datetime.now() }
    print(json.dumps(test_json,default=json_debug_handler))

if __name__ == '__main__':
    test_debug_json()

DEMO : http://ideone.com/hQJnLy http://ideone.com/hQJnLy

Output:

{"date": "2013-05-07T01:03:13.098727", "games": ["mario", "contra", "tetris"], "scores": {"pk": 45, "dp": 10}}

期望的输出:

{"date": "2013-05-07T01:03:13.098727", "games": { "orig": ["mario", "contra", "tetris"] ,"attrs" : { "src":"console"}} , "scores": { "orig": {"pk": 45, "dp": 10},"attrs": "processed":"unprocessed }}

是否default处理程序不适用于可序列化对象? 如果没有,我如何覆盖它,而不将 toJSON 方法添加到扩展类?

另外,这个版本的 JSON 编码器不起作用:

class JsonDebugEncoder(json.JSONEncoder):
    def default(self,obj):
        if  isinstance(obj, datetime.datetime):
            return obj.isoformat()
        elif isinstance(obj,mDict):
            return {'orig':obj , 'attrs': vars(obj)}
        elif isinstance(obj,mList):
            return {'orig':obj, 'attrs': vars(obj)}
        else:
            return json.JSONEncoder.default(self, obj)

如果有黑客攻击pickle,__getstate__,__setstate__,然后在 pickle.loads 对象上使用 json.dumps ,我也对此持开放态度,我尝试过,但这不起作用。


似乎要在给定的限制下实现您想要的行为,您必须深入研究JSONEncoder类一点。下面我写了一个自定义JSONEncoder覆盖iterencode传递自定义的方法isinstance方法_make_iterencode。它不是世界上最干净的东西,但考虑到选项似乎是最好的,并且它将定制保持在最低限度。

# customencoder.py
from json.encoder import (_make_iterencode, JSONEncoder,
                          encode_basestring_ascii, FLOAT_REPR, INFINITY,
                          c_make_encoder, encode_basestring)


class CustomObjectEncoder(JSONEncoder):

    def iterencode(self, o, _one_shot=False):
        """
        Most of the original method has been left untouched.

        _one_shot is forced to False to prevent c_make_encoder from
        being used. c_make_encoder is a funcion defined in C, so it's easier
        to avoid using it than overriding/redefining it.

        The keyword argument isinstance for _make_iterencode has been set
        to self.isinstance. This allows for a custom isinstance function
        to be defined, which can be used to defer the serialization of custom
        objects to the default method.
        """
        # Force the use of _make_iterencode instead of c_make_encoder
        _one_shot = False

        if self.check_circular:
            markers = {}
        else:
            markers = None
        if self.ensure_ascii:
            _encoder = encode_basestring_ascii
        else:
            _encoder = encode_basestring
        if self.encoding != 'utf-8':
            def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding):
                if isinstance(o, str):
                    o = o.decode(_encoding)
                return _orig_encoder(o)

        def floatstr(o, allow_nan=self.allow_nan,
                     _repr=FLOAT_REPR, _inf=INFINITY, _neginf=-INFINITY):
            if o != o:
                text = 'NaN'
            elif o == _inf:
                text = 'Infinity'
            elif o == _neginf:
                text = '-Infinity'
            else:
                return _repr(o)

            if not allow_nan:
                raise ValueError(
                    "Out of range float values are not JSON compliant: " +
                    repr(o))

            return text

        # Instead of forcing _one_shot to False, you can also just
        # remove the first part of this conditional statement and only
        # call _make_iterencode
        if (_one_shot and c_make_encoder is not None
                and self.indent is None and not self.sort_keys):
            _iterencode = c_make_encoder(
                markers, self.default, _encoder, self.indent,
                self.key_separator, self.item_separator, self.sort_keys,
                self.skipkeys, self.allow_nan)
        else:
            _iterencode = _make_iterencode(
                markers, self.default, _encoder, self.indent, floatstr,
                self.key_separator, self.item_separator, self.sort_keys,
                self.skipkeys, _one_shot, isinstance=self.isinstance)
        return _iterencode(o, 0)

您现在可以对CustomObjectEncoder因此它可以正确序列化您的自定义对象。这CustomObjectEncoder还可以做一些很酷的事情,比如处理嵌套对象。

# test.py
import json
import datetime
from customencoder import CustomObjectEncoder


class MyEncoder(CustomObjectEncoder):

    def isinstance(self, obj, cls):
        if isinstance(obj, (mList, mDict)):
            return False
        return isinstance(obj, cls)

    def default(self, obj):
        """
        Defines custom serialization.

        To avoid circular references, any object that will always fail
        self.isinstance must be converted to something that is
        deserializable here.
        """
        if isinstance(obj, datetime.datetime):
            return obj.isoformat()
        elif isinstance(obj, mDict):
            return {"orig": dict(obj), "attrs": vars(obj)}
        elif isinstance(obj, mList):
            return {"orig": list(obj), "attrs": vars(obj)}
        else:
            return None


class mList(list):
    pass


class mDict(dict):
    pass


def main():
    zelda = mList(['zelda'])
    zelda.src = "oldschool"
    games = mList(['mario', 'contra', 'tetris', zelda])
    games.src = 'console'
    scores = mDict({'dp': 10, 'pk': 45})
    scores.processed = "unprocessed"
    test_json = {'games': games, 'scores': scores,
                 'date': datetime.datetime.now()}
    print(json.dumps(test_json, cls=MyEncoder))

if __name__ == '__main__':
    main()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何更改可序列化 python 对象的 json 编码行为? 的相关文章

随机推荐

  • 使用 NSConnection 连接到“www.google.com”时出现错误

    使用连接到 www google com 时出现错误NSConnection 我找不到原因 任何帮助将不胜感激 NSString urkString www google com NSURL url NSURL URLWithString
  • 如何使用 C/C++ 预处理器生成一系列随机数

    我想生成一系列随机数C预处理器 并将它们存储在变量中以供我的程序使用 目标 我想在每次构建程序时生成一组 独特 的随机数 存储随机数的变量的一小部分将被有意义的 即非随机 数字覆盖 我希望黑客不可能通过调试程序或比较多个版本来区分有意义的数
  • 具体是什么将 x86 缓存行标记为脏 - 任何写入,或者是否需要显式更改?

    这个问题是具体来说针对现代 x86 64 缓存一致性架构 我很高兴答案在其他 CPU 上可能有所不同 如果我写入内存 MESI协议要求首先将缓存行读入缓存 然后在缓存中修改 该值被写入缓存行 然后标记为脏 在较旧的直写式微架构中 这将触发缓
  • Oozie 不断将旧版本的 httpcore jar 添加到类路径中

    我不断收到异常 因为 Oozie 将错误版本的 httpcore jar 添加到类路径中 我尝试了不同的选项 例如 oozie launcher mapreduce task classpath user precedence oozie
  • 如何设置 TextInputLayout 上计数器的颜色?

    我正在使用包裹在 EditText 周围的 TextInputLayout 现在柜台是黑色的 我希望它是白色的 我不确定要设置什么选项才能使其变为白色
  • Swift UITabBarController 用动画隐藏

    我试图在隐藏时向我的 tabBarController 添加动画 我能够用以下方法实现这种效果navigationBarController通过使用self navigationController isNavigationBarHidde
  • 想要一个实现“@include”的 AWK

    在 gawk 手册中我描述了一个 include操作员 这使您可以制作 awk 模块并共享脚本等 包含文件 到目前为止 我发现 Windows 的最新 cgywin mingw 和 gnu awk s awk gawk mawk nawk
  • 如何在Flutter中制作ArcProgress Bar?

    我正在尝试在 Flutter 中制作弧形进度条 下图是我想要实现的目标 我只能找到CircularProgressIndicator在 flutter 的 widget 目录中 我厌倦了以下包https pub dartlang org p
  • 部署中的密钥保管库值和链接的模板参数

    我有一个模板来创建密钥保管库和其中的秘密 我还有一个 Service Fabric 模板 它需要密钥保管库中的 3 个内容 保管库 URI 证书 URL 和证书指纹 如果我使用 powershell 创建密钥保管库和密钥 则可以轻松地从输出
  • navigator.mediaDevices 在 Chrome 62 的 iOS 上为 null?

    从最新版本的 Chrome 62 开始 仅在 iOS 11 设备下 当我尝试使用navigator mediaDevices 它是空的 文档中没有任何内容表明此功能已被删除 在此期间我开了一个Chrome 下的错误 https bugs c
  • 按特定字母对 JS 字符串数组进行排序

    我必须像这样对字符串数组进行排序 var arr akaw waka kawa akwa 排序类型必须是特定字母 在本例中为 W 因此我的函数必须返回此数组 arr waka kawa akwa akaw 这是一个动态数组 我不知道数组中有
  • 错误:任务“:app:processDebugAndroidTestManifest”执行失败

    这就是我更新 buildToolsVersion 时发生的情况26 0 1 to 26 0 2 错误 任务 all processDebugAndroidTestManifest 执行失败 清单合并失败 属性元数据 android supp
  • Android 应用程序中的所有图像都被视为图标吗?

    这已经困扰我一段时间了 我可能反应过度了 如果是的话请告诉我 但是 我觉得向 Android Studio 项目添加图像资源比应有的困难 不一定说这很难做到 但我觉得这应该是最容易做的事情之一 我对 AS 有点陌生 所以我在这里可能有点不合
  • 如何检测iPhone上的左/右滑动?

    有没有简单的方法来检测 iPhone 的此类手势 我可以使用touchesBegan touchesMoved touchesEnded 但我该如何实现这些手势呢 thz u 您将使用 UISwipeGestureRecognizer 对象
  • 绕着正方形滚动一个圆

    近一个月后 我仍然停留在这个问题上 我设法决定圆圈 或我所说的行人 是否应该向左 向右或向上 向下移动 但我需要有可能移动行人around一座建筑物 这意味着他们必须转角 基本上无论方向如何 他们只需要转90度 非常感谢 import nu
  • Python 中单下划线“_”变量的用途是什么?

    是什么意思 after for在这段代码中 if tbh bag n 0 for in tbh bag atom set n 1 Python 中有 3 个主要的常规用途 保存交互式中最后执行的表达式的结果 口译会议 参见docs http
  • 防止 iOS safari 移动网页窗口,以便发生拖动事件

    我使用 Pep js 进行多点触控上的动态拖动 但我的拖动事件没有被注册 因为当我尝试在 Safari 中拖动对象时 在 iOS 窗口中 窗口本身会移动并跟随我的拖动 如何防止浏览器窗口跟随我的拖动 以便 div 在我的网页中可以拖动吗 这
  • SPRING REST:请求被拒绝,因为未找到多部分边界

    我为 Spring 3 Rest 多部分文件上传做了一个 POC 它工作正常 但是当我尝试与我的应用程序集成时 我遇到了问题 它抛出以下异常 org springframework web multipart MultipartExcept
  • 是否可以创建没有锁的线程安全集合?

    这纯粹是出于兴趣问题 欢迎任何类型的问题 那么是否可以创建没有任何锁的线程安全集合呢 我所说的锁是指任何线程同步机制 包括互斥锁 信号量 甚至互锁 所有这些 是否可以在用户级别而不调用系统函数 好吧 可能实施效果不佳 我对理论上的可能性感兴
  • 如何更改可序列化 python 对象的 json 编码行为?

    更改不可 JSON 序列化的对象的格式很容易 例如 datetime datetime 出于调试目的 我的要求是改变一些自定义对象从基本对象扩展的方式 例如dict and list 以json格式序列化 代码 import datetim