Python jsons库序列化含属性类时字段重复,能否避免?
Python的jsons库序列化带@property的类时出现重复字段,如何避免?
问题背景
原本疑惑为什么jsons库序列化会出现带前置下划线的字段,现在已明确成因,但想解决数据重复序列化的问题。以下示例可复现问题:
示例1:字典序列化符合预期
import jsons with open('tmp.txt', 'w') as ofile: d = {'key': 'value'} ofile.write(jsons.dumps(d)) # 输出: # {"key": "value"}
示例2:普通类(对象)序列化符合预期
import jsons class Test: def __init__(self, value:str) -> None: self.value = value with open('tmp.txt', 'w') as ofile: test = Test('value') ofile.write(jsons.dumps(test)) # 输出: # {"value": "value"}
示例3:引入properties后出现重复输出
import jsons class TestProperty: def __init__(self, value:str) -> None: self.value = value @property def value(self) -> str: return self._value @value.setter def value(self, the_value) -> None: self._value = the_value with open('tmp.txt', 'w') as ofile: test = TestProperty('value') ofile.write(jsons.dumps(test)) # 输出: # {"_value": "value", "value": "value"}
示例4:改用getter/setter函数后问题消失
import jsons class TestFunction: def __init__(self, value:str) -> None: self.value = value def get_value(self) -> str: return self.value def set_value(self, the_value) -> None: self.value = the_value with open('tmp.txt', 'w') as ofile: test = TestFunction('value') ofile.write(jsons.dumps(test)) # 输出: # {"value": "value"}
重复原因
jsons库默认的序列化逻辑是:
- 遍历对象的所有实例属性(包括
_value这种以下划线开头的私有存储字段),将其加入序列化结果; - 同时,
@property装饰的方法会被识别为“类属性”,和普通实例属性一样被纳入序列化范围。
这就导致_value(实际存储数据的实例属性)和value(property提供的访问属性)都被序列化,出现重复。而示例4中的getter/setter是普通方法,jsons默认不会序列化方法,所以只保留了value实例属性,没有重复。
解决办法
方法1:序列化时排除指定字段
直接在dumps方法中指定要排除的字段,适合临时处理单个对象:
# 排除单个字段 jsons.dumps(test, exclude={'_value'}) # 通用规则:排除所有以_开头的属性 jsons.dumps(test, exclude=lambda attr_name: attr_name.startswith('_'))
方法2:在类定义时指定序列化规则
用@jsons.serializable装饰器标记类,明确指定要包含的字段,适合长期固定的类序列化规则:
import jsons @jsons.serializable(include=['value']) class TestProperty: def __init__(self, value:str) -> None: self.value = value @property def value(self) -> str: return self._value @value.setter def value(self, the_value) -> None: self._value = the_value # 序列化后仅输出{"value": "value"}
方法3:自定义序列化函数
针对特定类编写自定义序列化逻辑,适合复杂的定制需求:
import jsons class TestProperty: def __init__(self, value:str) -> None: self.value = value @property def value(self) -> str: return self._value @value.setter def value(self, the_value) -> None: self._value = the_value # 定义序列化函数 def serialize_test_property(obj): return {'value': obj.value} # 绑定到TestProperty类 jsons.set_serializer(serialize_test_property, TestProperty) # 序列化后仅输出{"value": "value"} test = TestProperty('value') jsons.dumps(test)
内容的提问来源于stack exchange,提问作者user2138149
相关产品推荐
相关产品推荐

