修改python jsonpickle源码, 实现不序列化对象私有成员(1)

问题及解决方案

jsonpickle是比较常用的序列化模块, 其特点是对于复杂的对象基本上都能够很好的序列化, 适用范围比较广.
有时候我们有需求, 希望私有变量能够不被序列化, 但是使用jsonpickle的自定义定制机制实现起来不太方便, 可以采用如下的方式:

class NoSerailPrivates:
    '''表示不序列化私有变量, 以_开头都变量'''
    def __getstate__(self):
        '''对于jsonpickle模块, 决定序列化哪些属性, 以'_'开头的属性不序列化'''
        state = self.__dict__.copy()
        # 创建一个临时副本进行迭代和删除操作
        temp_dict = state.copy()
        for key in temp_dict.keys():
            if key.startswith('_'): del state[key]
        return state
    def __setstate__(self, state):
        # 在这里执行初始化操作
        #self.__init__()    # 可以调用初始化函数, 初始化那些没有序列化的属性
        self.__dict__.update(state)

但是这种方式, 需要被序列化对象继承NoSerailPrivates或者在内部实现__getstate__, __setstate__, 另外, 如果对象包含子对象, 子对象也要做同样的事情.
当然, 还有别的办法, 比如注册自定义处理器, 但是也需要与被序列化类绑定, 并且对于子对象也需要绑定.
那么有没有办法可以对所有对象默认具有忽略私有成员的功能呢? 我目前还没有找到解决方案. 只能尝试修改源码了, 好在并不是很难.
下面讲一下主要修改步骤:

  1. 修改pickler.py文件中def _flatten_obj_instance(self, obj):函数. 这个函数负责把一个对象转换为序列化后的字符串.
    修改点: 增加一个exclude_privates=True参数选项, 这个选项是原本没有的, 是我新添加的. 用于后面是否过滤掉私有成员时判断.
return self._flatten_dict_obj(obj.__dict__, data, exclude=exclude, exclude_privates=True)
  1. 修改pickler.py文件中def _flatten_dict_obj(self, obj, data=None, exclude=(), exclude_privates=False):函数. 这个函数负责把(k,v)字典转换为序列化后的字符串.
    修改点:
    2.1 函数增加一个exclude_privates=False参数选项;
    2.2 在下面的代码中增加一个exclude_privates=exclude_privates参数选项, 这个选项的值继承自此函数的传入参数.
for k, v in util.items(obj, exclude=exclude, exclude_privates=exclude_privates):
  1. 修改util.py文件的def items(obj, exclude=(), exclude_privates=False):函数. 这个函数负责枚举字典的key,value并进行过滤.
    修改点:
    3.1 函数增加一个exclude_privates=False参数选项;
    3.2 函数实现代码修改如下, 提供对象私有成员过滤功能:
def items(obj, exclude=(), exclude_privates=False):
    """
    TODO: Replace all calls to this with plain dict.items()
    """
    for k, v in obj.items():
        if k in exclude:
            continue
        if exclude_privates:
            if isinstance(k,str) and k.startswith('_'):
                continue
        yield k, v

最后实现效果

测试代码如下:

import jsonpickle

class InnerClass:
    def __init__(self):
        self.public_var = 'hzqtest'
        self.__private_var = 20

class OuterClass:
    def __init__(self):
        self.public_var = 100
        self.__private_var = 200
        self.inner = InnerClass()  # 嵌套对象

obj = OuterClass()
#obj = {'hzqtest':10,'_abc':100}
json_str = jsonpickle.encode(obj)
print(json_str)  # 输出应仅包含 public_var

输出信息: {"py/object": "__main__.OuterClass", "public_var": 100, "inner": {"py/object": "__main__.InnerClass", "public_var": "hzqtest"}}
由此可见, 对象私有成员被屏蔽.

posted @ 2024-12-18 22:22  顺其自然,道法自然  阅读(12)  评论(0编辑  收藏  举报