如何解决Python 序列化类并使用 JsonPickle 更改属性大小写
使用 Python 和 JsonPickle,如何使用特定大小写(例如 Camel Case、Pascal 等)序列化对象?下面的答案是手动完成的,但是寻找特定的 Jsonpickle 解决方案,因为它可以处理复杂的对象类型。
JSON serialize a class and change property casing with Python
https://stackoverflow.com/a/8614096/15435022
class HardwareSystem:
def __init__(self,vm_size):
self.vm_size = vm_size
self.some_other_thing = 42
self.a = 'a'
def snake_to_camel(s):
a = s.split('_')
a[0] = a[0].lower()
if len(a) > 1:
a[1:] = [u.title() for u in a[1:]]
return ''.join(a)
def serialise(obj):
return {snake_to_camel(k): v for k,v in obj.__dict__.items()}
hp = HardwareSystem('Large')
print(json.dumps(serialise(hp),indent=4,default=serialise))
解决方法
这是我的尝试。
from importlib import import_module
import inspect
import json
import jsonpickle
import re
def snake_to_camel(s):
a = s.split('_')
a[0] = a[0].lower()
if len(a) > 1:
a[1:] = [u.title() for u in a[1:]]
return ''.join(a)
def camel_to_snake(s):
snake = []
snake_len = len(s)
for idx,char in enumerate(s):
snake.append(char.lower())
if idx < snake_len - 1:
if char.islower() and s[idx+1].isupper():
snake.append('_')
return ''.join(snake)
def debug_output(obj):
output = '{}({})'
attrs = [attr + '=' + repr(getattr(obj,attr)) for attr in vars(obj)]
return output.format(obj.__class__.__name__,','.join(attrs))
class SoftwareSystem:
def __init__(self):
self.software_rating = 'Awesome!'
# Making debug output friendly
def __repr__(self):
return debug_output(self)
class HardwareSystem:
def __init__(self,vm_size):
self.vm_size = vm_size
self.some_other_thing = 42
self.a = 'a'
# Making debug output friendly
def __repr__(self):
return debug_output(self)
@jsonpickle.handlers.register(HardwareSystem,base=True)
@jsonpickle.handlers.register(SoftwareSystem,base=True)
class SystemHandler(jsonpickle.handlers.BaseHandler):
def flatten(self,obj,data):
for k,v in obj.__dict__.items():
data[snake_to_camel(k)] = jsonpickle.encode(v)
return data
def restore(self,obj):
# Gets reference to class
# https://stackoverflow.com/a/55559852/152016
module_path,class_name = obj['py/object'].rsplit('.',1)
module = import_module(module_path)
class_ = getattr(module,class_name)
# Dealing with __init__ params (except first)
params = inspect.getargs(class_.__init__.__code__)
params = params.args[1:]
# Preparing dict keys
l_obj = {}
for k,v in obj.items():
l_obj[camel_to_snake(k)] = v
# Instantiating constructor params
data = {}
for k,v in l_obj.items():
if k in params:
data[k] = v
result = class_(**data)
# Setting other jsonpickled object attributes
for k,v in l_obj.items():
if not k in params:
setattr(result,k,v)
return result
hw = HardwareSystem(100)
sw = SoftwareSystem()
hw.software_instance = sw
json_str = jsonpickle.encode(hw)
print(json_str)
decoded = jsonpickle.decode(json_str)
print(hw)
这里有一些假设:
- 按照您原来的
snake_to_camel
函数,我在解码上放置了一个camel_to_snake
,它假设只有小写字母后的第一个大写字母才会在_
字符前面加上awesomeABC
awesome_abc
将翻译为awesomeAbc
,因此,如果您再次将其翻译回来,它将错误地__init__
) - 以上代码对在
hw.software_instance
之后添加的属性进行编码/解码(参见上面的debug_output
示例)。 - 您可以嵌套对象。我只试过一个嵌套的对象。
- 我添加了辅助
__repr__
/import re preposition_lst = ['DE LO','DE LA','DE LAS','DE LES','DEL','DELS','DO','DA','DOS','DAS','DE'] cases = ["DE BLAS ZAPATA","MATIAS DE LA MANO","LOPEZ FERNANDEZ DE VILLAVERDE","DE MIGUEL DEL CORRAL","VIDAL DE LA PENA SOLIS","MONTAVA DEL ARCO","DOS CASAS VALLE"] def split_name(name): f1 = re.compile("(.*)({preps}(.+))".format(preps = "(" + " |".join(preposition_lst) + ")")) m1 = f1.match(case) if m1: if len(m1.group(1)) != 0: return m1.group(1).strip(),m1.group(2).strip() else: return " ".join(name.split()[:-1]),name.split()[-1] else: return " ".join(name.split()[:-1]),name.split()[-1] for case in cases: first,second = split_name(case) print("{} --> name 1 = {},name 2 = {}".format(case,first,second)) # DE BLAS ZAPATA --> name 1 = DE BLAS,name 2 = ZAPATA # MATIAS DE LA MANO --> name 1 = MATIAS,name 2 = DE LA MANO # LOPEZ FERNANDEZ DE VILLAVERDE --> name 1 = LOPEZ FERNANDEZ,name 2 = DE VILLAVERDE # DE MIGUEL DEL CORRAL --> name 1 = DE MIGUEL,name 2 = DEL CORRAL # VIDAL DE LA PENA SOLIS --> name 1 = VIDAL,name 2 = DE LA PENA SOLIS # MONTAVA DEL ARCO --> name 1 = MONTAVA,name 2 = DEL ARCO # DOS CASAS VALLE --> name 1 = DOS CASAS,name 2 = VALLE
函数,你可以把它们扔掉(或自定义 :))
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。