代码之家  ›  专栏  ›  技术社区  ›  mattsmith5

Python使用JsonPickle序列化类并更改属性大小写

  •  0
  • mattsmith5  · 技术社区  · 5 年前

    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))
    
    0 回复  |  直到 5 年前
        1
  •  2
  •   Niloct    5 年前

    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 在解码时,假定只有小写字母后的第一个大写字母将在 _ char(so awesomeABC 将转化为 awesome_abc awesomeAbc )
    • 上述代码编码/解码后添加的属性 __init__ (例如,见 hw.software_instance 上文)。
    • 我添加了辅助项 debug_output / __repr__ 函数,您可以将其丢弃(或自定义:)