How to reduce boilerplate when initializating classes from JSONs in Python 3.5?

柔情痞子 提交于 2020-01-17 06:03:58

问题


I have a set of python webservices that work with data objects they get via a JSON POSTs. In my old services I have a lot of boilerplate to (de)serialize and check JSONs for each object. With Python 3.5s new typing and PEP 484 I have the feeling that could be substantially reduced. Is it worth it? Does anyone have a good solution for it?

Additional info

My old boilerplate looks like this for every object:

class Data:

    class Nested1:
        def __init__(self, nested1_flat1):
            self.nested1_flat1 = nested1_flat1

        @classmethod
        def from_jsond(cls, jsond):
            # jsond : dict of strings, lists and dicts as usually receivied from reading JSON
            kwargs = {}
            for key, val in jsond.items():
                # lots of code to deal with special objects , e.g.
                if key=='date' : kwargs[key] = cleverly_build_datetime_from_js_format(val)
            return cls.__init__(**kwargs)

    def __init__(self, flat1, nested1):
        self.flat1 = flat1
        self.nested1 = nested1

    @classmethod
    def from_jsond(cls, jsond):
        kwargs = {}
        for key, val in jsond.items():
            # lots of code to deal with nested and special objects, e.g.
            if key=='nested1' : kwargs[key] = Nested1.from_jsond(val)
        return cls.__init__(**kwargs)

I managed to reduce it down to the following

@from_jsond
class Data:

    @from_jsond
    class Nested1:

        @auto_assign
        @beartype
        def __init__(self, nested1_flat1: str):
            pass

    @auto_assign
    @beartype
    def __init__(self, flat1: str, nested1: Nested1)
        pass

Here I used snippets for @auto_assign and @beartype and my own from_jsond.

import inspect
from typing import Any

_JSON_READABLE = [str, list, dict, Any]

def _from_jsond(cls, json_dict):
    '''
    Entity specific conversion of string dictionary to entity.
    The json_dict is a dict of string, lists and other dicts as typically encoded in a JSON.
    '''
    kwargs = {}
    init_parameters = inspect.signature(cls.__init__).parameters
    for key, val in json_dict.items():
        if key in init_parameters.keys():
            if init_parameters[key].annotation in _JSON_READABLE:
                kwargs[key] = val
            else:
                if hasattr(init_parameters[key].annotation, 'from_jsond'):
                    kwargs[key] = init_parameters[key].annotation.from_jsond(val)
                else:
                    raise TypeError('No method to unserialize type "' + init_parameters[key].annotation.__name__ +  '"')
        else:
            raise AttributeError('Class "' + cls.__name__   + '" does not accept attribute "' + key + '"')
    return cls(**kwargs)

def from_jsond(cls):
    ''' Wrapper to add _from_jsonlike to cls as classmethod '''

    cls.from_jsonlike = classmethod(_from_jsond)
    return cls

With inheritance one could most likely reduce it even further, but I don't know if it is all worth the hassle and stable enough. Opinions and experiences are welcome :)


回答1:


No, PEP 484 and type hints in general will not help you reduce the boilerplate.

The simplest explanation is that python run-time is not aware of PEP 484. Python interpreter executes type hints only to make sure the syntax is correct, there are no undefined names, etc.

Therefore, there is no way to meaningfully change the run-time behavior of your program by using type hints.

Type hints are only processed in a separate phase, before you execute the interpreter, to verify that your types are correct. No information flows from that analysis to the python interpreter.

Of course you can read type annotations for your source code in run-time yourself, and then do what you want with them. But that's clearly not what you're asking, since in order to do anything useful with that approach, you'd have to write a lot of rather complex code.



来源:https://stackoverflow.com/questions/39097411/how-to-reduce-boilerplate-when-initializating-classes-from-jsons-in-python-3-5

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!